diff --git a/docs/doxygen/include/size_table.md b/docs/doxygen/include/size_table.md index e144167e..ec01ba4a 100644 --- a/docs/doxygen/include/size_table.md +++ b/docs/doxygen/include/size_table.md @@ -24,7 +24,7 @@ cellular_common_api.c -
0.5K
+
0.6K
0.5K
@@ -44,7 +44,7 @@ Total estimates -
14.0K
+
14.1K
12.8K
diff --git a/modules/hl7802/cellular_hl7802_api.c b/modules/hl7802/cellular_hl7802_api.c index 632b0319..823953f2 100644 --- a/modules/hl7802/cellular_hl7802_api.c +++ b/modules/hl7802/cellular_hl7802_api.c @@ -88,6 +88,10 @@ #define KSELACQ_RAT_NBIOT_CHAR ( '2' ) #define KSELACQ_RAT_GSM_CHAR ( '3' ) +#define CELLULAR_PORT_NUM_CHAR_LEN ( 6 ) + +#define CELLULAR_REMOTE_IP_ADDR_MAX_LENGTH ( 127 ) + /*-----------------------------------------------------------*/ /** @@ -513,6 +517,8 @@ static CellularError_t buildSocketConfig( CellularSocketHandle_t socketHandle, char * pCmdBuf ) { CellularError_t cellularStatus = CELLULAR_SUCCESS; + /* +1 size in buffer for ',' */ + char portBuf[ CELLULAR_PORT_NUM_CHAR_LEN + 1 ] = { 0 }; if( pCmdBuf == NULL ) { @@ -525,18 +531,38 @@ static CellularError_t buildSocketConfig( CellularSocketHandle_t socketHandle, socketHandle->socketProtocol ) ); cellularStatus = CELLULAR_UNSUPPORTED; } + else if( strlen( socketHandle->remoteSocketAddress.ipAddress.ipAddress ) > CELLULAR_REMOTE_IP_ADDR_MAX_LENGTH ) + { + /* The maximum length of domain name is 127 in HL7802. */ + LogError( ( "buildSocketConfig: the remote server's address is too long, length=%u", + strlen( socketHandle->remoteSocketAddress.ipAddress.ipAddress ) ) ); + cellularStatus = CELLULAR_UNSUPPORTED; + } else { /* Form the AT command. */ /* The return value of snprintf is not used. - * The max length of the string is fixed and checked offline. */ + * The max length of the string is fixed and checked offline. + * Reserve buffer for port setting. */ /* coverity[misra_c_2012_rule_21_6_violation]. */ - ( void ) snprintf( pCmdBuf, CELLULAR_AT_CMD_MAX_SIZE, + ( void ) snprintf( pCmdBuf, CELLULAR_AT_CMD_MAX_SIZE - sizeof( portBuf ), "AT+KTCPCFG=%u,0,\"%s\",%u", socketHandle->contextId, socketHandle->remoteSocketAddress.ipAddress.ipAddress, socketHandle->remoteSocketAddress.port ); + + /* Set the local port in the end of command buffer string if localPort is not 0. */ + if( socketHandle->localPort > 0 ) + { + ( void ) snprintf( portBuf, sizeof( portBuf ), + ",%u", + socketHandle->localPort ); + + /* Because the length of host's IP address is limited, + * the buffer size must be enough for port setting. */ + strcat( pCmdBuf, portBuf ); + } } return cellularStatus; diff --git a/modules/sara_r4/cellular_r4_api.c b/modules/sara_r4/cellular_r4_api.c index 70f7f065..679a450d 100644 --- a/modules/sara_r4/cellular_r4_api.c +++ b/modules/sara_r4/cellular_r4_api.c @@ -128,6 +128,9 @@ static CellularError_t controlSignalStrengthIndication( CellularContext_t * pCon CellularError_t Cellular_SetPsmSettings( CellularHandle_t cellularHandle, const CellularPsmSettings_t * pPsmSettings ); +static CellularError_t _Cellular_isSockOptSupport( CellularSocketOptionLevel_t optionLevel, + CellularSocketOption_t option ); + /*-----------------------------------------------------------*/ static CellularPktStatus_t socketRecvDataPrefix( void * pCallbackContext, @@ -2736,6 +2739,29 @@ CellularError_t Cellular_SetPsmSettings( CellularHandle_t cellularHandle, /*-----------------------------------------------------------*/ +static CellularError_t _Cellular_isSockOptSupport( CellularSocketOptionLevel_t optionLevel, + CellularSocketOption_t option ) +{ + CellularError_t err = CELLULAR_UNSUPPORTED; + + if( ( optionLevel == CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT ) && + ( ( option == CELLULAR_SOCKET_OPTION_SEND_TIMEOUT ) || + ( option == CELLULAR_SOCKET_OPTION_RECV_TIMEOUT ) || + ( option == CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID ) ) ) + { + err = CELLULAR_SUCCESS; + } + else + { + LogWarn( ( "Cellular_SocketSetSockOpt: Option [Level:option=%d:%d] not supported in SARA R4", + optionLevel, option ) ); + } + + return err; +} + +/*-----------------------------------------------------------*/ + /* FreeRTOS Cellular Library API. */ /* coverity[misra_c_2012_rule_8_7_violation] */ CellularError_t Cellular_SetEidrxSettings( CellularHandle_t cellularHandle, @@ -2825,3 +2851,26 @@ CellularError_t Cellular_Init( CellularHandle_t * pCellularHandle, } /*-----------------------------------------------------------*/ + +/* FreeRTOS Cellular Library API. */ +CellularError_t Cellular_SocketSetSockOpt( CellularHandle_t cellularHandle, + CellularSocketHandle_t socketHandle, + CellularSocketOptionLevel_t optionLevel, + CellularSocketOption_t option, + const uint8_t * pOptionValue, + uint32_t optionValueLength ) +{ + CellularError_t err = CELLULAR_SUCCESS; + + err = _Cellular_isSockOptSupport( optionLevel, option ); + + if( err == CELLULAR_SUCCESS ) + { + err = Cellular_CommonSocketSetSockOpt( cellularHandle, socketHandle, optionLevel, option, + pOptionValue, optionValueLength ); + } + + return err; +} + +/*-----------------------------------------------------------*/ diff --git a/modules/sara_r4/cellular_r4_wrapper.c b/modules/sara_r4/cellular_r4_wrapper.c index bffb9ff5..5e629c4f 100644 --- a/modules/sara_r4/cellular_r4_wrapper.c +++ b/modules/sara_r4/cellular_r4_wrapper.c @@ -123,21 +123,6 @@ CellularError_t Cellular_CreateSocket( CellularHandle_t cellularHandle, /*-----------------------------------------------------------*/ -/* FreeRTOS Cellular Library API. */ -/* coverity[misra_c_2012_rule_8_7_violation] */ -CellularError_t Cellular_SocketSetSockOpt( CellularHandle_t cellularHandle, - CellularSocketHandle_t socketHandle, - CellularSocketOptionLevel_t optionLevel, - CellularSocketOption_t option, - const uint8_t * pOptionValue, - uint32_t optionValueLength ) -{ - return Cellular_CommonSocketSetSockOpt( cellularHandle, socketHandle, optionLevel, option, - pOptionValue, optionValueLength ); -} - -/*-----------------------------------------------------------*/ - /* FreeRTOS Cellular Library API. */ /* coverity[misra_c_2012_rule_8_7_violation] */ CellularError_t Cellular_SocketRegisterDataReadyCallback( CellularHandle_t cellularHandle, diff --git a/source/cellular_common_api.c b/source/cellular_common_api.c index 3ae081bd..fc81733d 100644 --- a/source/cellular_common_api.c +++ b/source/cellular_common_api.c @@ -97,14 +97,27 @@ static CellularError_t _socketSetSockOptLevelTransport( CellularSocketOption_t o } else if( option == CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID ) { - if( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) + if( ( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) && ( optionValueLength == sizeof( uint8_t ) ) ) { socketHandle->contextId = *pOptionValue; } else { - LogError( ( "Cellular_SocketSetSockOpt: Cannot change the contextID in this state %d", - socketHandle->socketState ) ); + LogError( ( "Cellular_SocketSetSockOpt: Cannot change the contextID in this state %d or length %d is invalid.", + socketHandle->socketState, optionValueLength ) ); + cellularStatus = CELLULAR_INTERNAL_FAILURE; + } + } + else if( option == CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT ) + { + if( ( socketHandle->socketState == SOCKETSTATE_ALLOCATED ) && ( optionValueLength == sizeof( uint16_t ) ) ) + { + socketHandle->localPort = *( ( uint16_t * ) pOptionValue ); + } + else + { + LogError( ( "Cellular_SocketSetSockOpt: Cannot change the localPort in this state %d or length %d is invalid.", + socketHandle->socketState, optionValueLength ) ); cellularStatus = CELLULAR_INTERNAL_FAILURE; } } diff --git a/source/include/cellular_types.h b/source/include/cellular_types.h index 3bbfb184..97266f28 100644 --- a/source/include/cellular_types.h +++ b/source/include/cellular_types.h @@ -324,7 +324,8 @@ typedef enum CellularSocketOption CELLULAR_SOCKET_OPTION_MAX_IP_PACKET_SIZE, /**< Set Max IP packet size. */ CELLULAR_SOCKET_OPTION_SEND_TIMEOUT, /**< Set send timeout (in milliseconds). */ CELLULAR_SOCKET_OPTION_RECV_TIMEOUT, /**< Set receive timeout (in milliseconds). */ - CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID /**< Set PDN Context ID to use for the socket. */ + CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID, /**< Set PDN Context ID to use for the socket. */ + CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT /**< Set local port. */ } CellularSocketOption_t; /** diff --git a/test/unit-test/cellular_common_api_utest.c b/test/unit-test/cellular_common_api_utest.c index 7ea7d4b8..c9bc2288 100644 --- a/test/unit-test/cellular_common_api_utest.c +++ b/test/unit-test/cellular_common_api_utest.c @@ -785,7 +785,7 @@ void test_Cellular_CommonSocketSetSockOpt_Option_PdnContextId_Happy_Path( void ) cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID, - ( const uint8_t * ) &optionValue, sizeof( uint32_t ) ); + ( const uint8_t * ) &optionValue, sizeof( uint8_t ) ); TEST_ASSERT_EQUAL( CELLULAR_SUCCESS, cellularStatus ); } @@ -806,6 +806,30 @@ void test_Cellular_CommonSocketSetSockOpt_Option_PdnContextId_Failure_Path( void _Cellular_CheckLibraryStatus_IgnoreAndReturn( CELLULAR_SUCCESS ); + cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, + CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, + CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID, + ( const uint8_t * ) &optionValue, sizeof( uint8_t ) ); + + TEST_ASSERT_EQUAL( CELLULAR_INTERNAL_FAILURE, cellularStatus ); +} + +/** + * @brief Test that option pdn context id failure path case with wrong size for Cellular_CommonSocketSetSockOpt. + */ +void test_Cellular_CommonSocketSetSockOpt_Option_PdnContextId_WrongSize_Failure_Path( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t context; + + memset( &context, 0, sizeof( CellularContext_t ) ); + struct CellularSocketContext socketHandle; + uint32_t optionValue = 0; + + socketHandle.socketState = SOCKETSTATE_ALLOCATED; + + _Cellular_CheckLibraryStatus_IgnoreAndReturn( CELLULAR_SUCCESS ); + cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID, @@ -832,7 +856,7 @@ void test_Cellular_CommonSocketSetSockOpt_Option_Unsupported_Failure_Path( void cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, - CELLULAR_SOCKET_OPTION_PDN_CONTEXT_ID + 1, + CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT + 1, ( const uint8_t * ) &optionValue, sizeof( uint32_t ) ); TEST_ASSERT_EQUAL( CELLULAR_UNSUPPORTED, cellularStatus ); @@ -1024,3 +1048,78 @@ void test_Cellular_CommonSocketRegisterClosedCallback_Happy_Path( void ) TEST_ASSERT_EQUAL( socketHandle.closedCallback, cellularSocketClosedCallback ); TEST_ASSERT_EQUAL( socketHandle.pClosedCallbackContext, testCallback ); } + +/** + * @brief Test that option set local port happy path case for Cellular_CommonSocketSetSockOpt. + */ +void test_Cellular_CommonSocketSetSockOpt_Option_SetLocalPort_Happy_Path( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t context; + + memset( &context, 0, sizeof( CellularContext_t ) ); + struct CellularSocketContext socketHandle = { 0 }; + uint16_t optionValue = 12345; + + socketHandle.socketState = SOCKETSTATE_ALLOCATED; + + _Cellular_CheckLibraryStatus_IgnoreAndReturn( CELLULAR_SUCCESS ); + + cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, + CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, + CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT, + ( const uint8_t * ) &optionValue, sizeof( uint16_t ) ); + + TEST_ASSERT_EQUAL( optionValue, socketHandle.localPort ); + TEST_ASSERT_EQUAL( CELLULAR_SUCCESS, cellularStatus ); +} + +/** + * @brief Test that option set local port at wrong socket state for Cellular_CommonSocketSetSockOpt. + */ +void test_Cellular_CommonSocketSetSockOpt_Option_SetLocalPort_Failure_Path( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t context; + + memset( &context, 0, sizeof( CellularContext_t ) ); + struct CellularSocketContext socketHandle = { 0 }; + uint16_t optionValue = 12345; + + socketHandle.socketState = SOCKETSTATE_CONNECTING; + + _Cellular_CheckLibraryStatus_IgnoreAndReturn( CELLULAR_SUCCESS ); + + cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, + CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, + CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT, + ( const uint8_t * ) &optionValue, sizeof( uint16_t ) ); + + TEST_ASSERT_EQUAL( CELLULAR_INTERNAL_FAILURE, cellularStatus ); + TEST_ASSERT_EQUAL( 0, socketHandle.localPort ); +} + +/** + * @brief Test that option set local port failure path case with wrong size for Cellular_CommonSocketSetSockOpt. + */ +void test_Cellular_CommonSocketSetSockOpt_Option_SetLocalPort_WrongSize_Failure_Path( void ) +{ + CellularError_t cellularStatus = CELLULAR_SUCCESS; + CellularContext_t context; + + memset( &context, 0, sizeof( CellularContext_t ) ); + struct CellularSocketContext socketHandle = { 0 }; + uint16_t optionValue = 12345; + + socketHandle.socketState = SOCKETSTATE_ALLOCATED; + + _Cellular_CheckLibraryStatus_IgnoreAndReturn( CELLULAR_SUCCESS ); + + cellularStatus = Cellular_CommonSocketSetSockOpt( &context, &socketHandle, + CELLULAR_SOCKET_OPTION_LEVEL_TRANSPORT, + CELLULAR_SOCKET_OPTION_SET_LOCAL_PORT, + ( const uint8_t * ) &optionValue, sizeof( uint32_t ) ); + + TEST_ASSERT_EQUAL( CELLULAR_INTERNAL_FAILURE, cellularStatus ); + TEST_ASSERT_EQUAL( 0, socketHandle.localPort ); +}