diff --git a/source/AdvSecurityDml/cosa_adv_security_internal.c b/source/AdvSecurityDml/cosa_adv_security_internal.c index f722552..6293c16 100644 --- a/source/AdvSecurityDml/cosa_adv_security_internal.c +++ b/source/AdvSecurityDml/cosa_adv_security_internal.c @@ -150,6 +150,7 @@ pthread_mutex_t logMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t logCond = PTHREAD_COND_INITIALIZER; static BOOL logReady = FALSE; static char prevWanIfname[MAX_INTERFACE_SIZE] = {0}; +STATIC char prevBridgeMode[2] = {0}; void advsec_handle_sysevent_async(void); static void advsec_start_logger_thread(void); @@ -2349,6 +2350,22 @@ void advsec_handle_sysevent_notification(char *event, char *val) { if(type == SYSEVENT_BRIDGE_MODE_EVENT) { + BOOL updatePrevMode = FALSE; + + if((val[0] == '\0') || (val[1] != '\0')) + { + CcspTraceWarning(("CcspAdvSecurity: Invalid bridge mode value '%s'\n", val)); + return; + } + + rc = strcmp_s(prevBridgeMode, sizeof(prevBridgeMode), val, &ind); + ERR_CHK(rc); + if((rc == EOK) && (ind == 0)) + { + CcspTraceInfo(("CcspAdvSecurity: Bridge mode unchanged '%s', no action needed\n", val)); + return; + } + if((val[0] == '0') && (val[1] == '\0')) { CcspTraceWarning(("CcspAdvSecurity: Received Bridge Mode Off\n")); @@ -2357,13 +2374,17 @@ void advsec_handle_sysevent_notification(char *event, char *val) { CcspTraceWarning(("Failure in executing command via v_secure_system. ret val: %d \n", ret)); } + else + { + updatePrevMode = TRUE; + } } #ifndef _XF3_PRODUCT_REQ_ - if((val[0] == '2') && (val[1] == '\0')) + else if((val[0] == '2') && (val[1] == '\0')) #else - if((val[0] == '3') && (val[1] == '\0')) + else if((val[0] == '3') && (val[1] == '\0')) #endif { CcspTraceWarning(("CcspAdvSecurity: Received Bridge Mode On\n")); @@ -2372,6 +2393,21 @@ void advsec_handle_sysevent_notification(char *event, char *val) { CcspTraceWarning(("Failure in executing command via v_secure_system. ret val: %d \n", ret)); } + else + { + updatePrevMode = TRUE; + } + + } + else + { + updatePrevMode = TRUE; + } + + if(updatePrevMode) + { + rc = strcpy_s(prevBridgeMode, sizeof(prevBridgeMode), val); + ERR_CHK(rc); } } diff --git a/source/AdvSecurityDml/cosa_adv_security_internal.h b/source/AdvSecurityDml/cosa_adv_security_internal.h index 9fcce96..560e5b5 100644 --- a/source/AdvSecurityDml/cosa_adv_security_internal.h +++ b/source/AdvSecurityDml/cosa_adv_security_internal.h @@ -19,6 +19,12 @@ #ifndef _COSA_ADV_SEC_INTERNAL_H #define _COSA_ADV_SEC_INTERNAL_H +#ifndef UNIT_TEST_DOCKER_SUPPORT +#define STATIC static +#else +#define STATIC +#endif + #include "ansc_platform.h" #include "ansc_string_util.h" @@ -216,6 +222,7 @@ ANSC_STATUS Wifi_GetParameterValue(const char *pParamName, char *pReturnVal); BOOL WifiMgmtFrame_GetActive_Status(void); BOOL WifiLevl_GetActive_Status(void); int wifidcl_init_precheck(void); +void advsec_handle_sysevent_notification(char *event, char *val); ANSC_HANDLE CosaSecurityCreate diff --git a/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityInternalTest.cpp b/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityInternalTest.cpp index 0f3b8e2..3857462 100644 --- a/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityInternalTest.cpp +++ b/source/test/CcspAdvSecurityDmlTest/CcspAdvSecurityInternalTest.cpp @@ -18,9 +18,14 @@ #include "CcspAdvSecurityMock.h" +static char BRIDGE_MODE_EVENT_NAME[] = "bridge_mode"; + +extern "C" char prevBridgeMode[2]; + class CcspAdvSecurityInternalTestFixture : public ::testing::Test { protected: void SetUp() override { + prevBridgeMode[0] = '\0'; g_syscfgMock = new SyscfgMock(); g_securewrapperMock = new SecureWrapperMock(); @@ -1163,6 +1168,196 @@ TEST_F(CcspAdvSecurityInternalTestFixture, CosaAdvSecGetLookupTimeoutExceededCou EXPECT_EQ(CosaAdvSecGetLookupTimeoutExceededCount(), lcount); } +TEST_F(CcspAdvSecurityInternalTestFixture, advsec_handle_sysevent_notification_InvalidBridgeModeValue) +{ + char invalidValue[] = "00"; + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("bridge_mode"), _, _, _, _, _)) + .Times(::testing::AtLeast(1)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcpy_s_chk(_, _, _, _)) + .Times(0); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(_, _)) + .Times(0); + + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, invalidValue); +} + +TEST_F(CcspAdvSecurityInternalTestFixture, advsec_handle_sysevent_notification_IntermediateBridgeModeValueNoFirewallAction) +{ + // Bridge mode value "1" is a real state transition . + // prevBridgeMode must still be updated so subsequent transitions are + // correctly detected, but no firewall command should fire since only + // '0' and '2'/'3' trigger enable/disable actions. + char intermediateValue[] = "1"; + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("bridge_mode"), _, _, _, _, _)) + .Times(::testing::AtLeast(1)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(_, _, StrEq("1"), _, _, _)) + .Times(::testing::AtLeast(1)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(1), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcpy_s_chk(_, _, _, _)) + .Times(1) + .WillOnce(Return(EOK)); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(_, _)) + .Times(0); + + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, intermediateValue); +} + +TEST_F(CcspAdvSecurityInternalTestFixture, advsec_handle_sysevent_notification_BridgeModeUnchangedNoAction) +{ + char bridgeModeOff[] = "0"; + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("bridge_mode"), _, _, _, _, _)) + .Times(::testing::AtLeast(2)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(_, _, StrEq("0"), _, _, _)) + .Times(::testing::AtLeast(2)) + .WillOnce(DoAll( + SetArgPointee<3>(1), + Return(EOK) + )) + .WillOnce(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcpy_s_chk(_, _, _, _)) + .Times(1) + .WillOnce(Return(EOK)); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(HasSubstr("/usr/ccsp/advsec/start_adv_security.sh -enable &"), _)) + .Times(1) + .WillOnce(Return(0)); + + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); +} + +TEST_F(CcspAdvSecurityInternalTestFixture, advsec_handle_sysevent_notification_BridgeModeRetryOnCommandFailure) +{ + char bridgeModeOff[] = "0"; + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("bridge_mode"), _, _, _, _, _)) + .Times(::testing::AtLeast(2)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(_, _, StrEq("0"), _, _, _)) + .Times(2) + .WillRepeatedly(DoAll( + SetArgPointee<3>(1), + Return(EOK) + )); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(HasSubstr("/usr/ccsp/advsec/start_adv_security.sh -enable &"), _)) + .Times(2) + .WillOnce(Return(1)) + .WillOnce(Return(0)); + EXPECT_CALL(*g_safecLibMock, _strcpy_s_chk(_, _, _, _)) + .Times(1) + .WillOnce(Return(EOK)); + + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); +} + +TEST_F(CcspAdvSecurityInternalTestFixture, advsec_handle_sysevent_notification_BridgeModeTransitionActionsOnChangeOnly) +{ + char bridgeModeOff[] = "0"; +#ifndef _XF3_PRODUCT_REQ_ + char bridgeModeOn[] = "2"; +#else + char bridgeModeOn[] = "3"; +#endif + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("bridge_mode"), _, _, _, _, _)) + .Times(::testing::AtLeast(2)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(_, _, StrEq("0"), _, _, _)) + .Times(2) + .WillOnce(DoAll( + SetArgPointee<3>(1), + Return(EOK) + )) + .WillOnce(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcpy_s_chk(_, _, _, _)) + .Times(1) + .WillOnce(Return(EOK)); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(HasSubstr("/usr/ccsp/advsec/start_adv_security.sh -enable &"), _)) + .Times(1) + .WillOnce(Return(0)); + + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); + + ::testing::Mock::VerifyAndClearExpectations(g_safecLibMock); + ::testing::Mock::VerifyAndClearExpectations(g_securewrapperMock); + + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(StrEq("bridge_mode"), _, _, _, _, _)) + .Times(::testing::AtLeast(4)) + .WillRepeatedly(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(_, _, StrEq(bridgeModeOn), _, _, _)) + .Times(2) + .WillOnce(DoAll( + SetArgPointee<3>(1), + Return(EOK) + )) + .WillOnce(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcmp_s_chk(_, _, StrEq("0"), _, _, _)) + .Times(2) + .WillOnce(DoAll( + SetArgPointee<3>(1), + Return(EOK) + )) + .WillOnce(DoAll( + SetArgPointee<3>(0), + Return(EOK) + )); + EXPECT_CALL(*g_safecLibMock, _strcpy_s_chk(_, _, _, _)) + .Times(2) + .WillRepeatedly(Return(EOK)); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(HasSubstr("/usr/ccsp/advsec/start_adv_security.sh -disable &"), _)) + .Times(1) + .WillOnce(Return(0)); + EXPECT_CALL(*g_securewrapperMock, v_secure_system(HasSubstr("/usr/ccsp/advsec/start_adv_security.sh -enable &"), _)) + .Times(1) + .WillOnce(Return(0)); + + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOn); + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOn); + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); + advsec_handle_sysevent_notification(BRIDGE_MODE_EVENT_NAME, bridgeModeOff); +} + TEST_F(CcspAdvSecurityInternalTestFixture, CosaRabidSetMemoryLimit) { const char *RabidMemoryLimit = "Advsecurity_RabidMemoryLimit";