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 );
+}