diff --git a/source/hotspotfd/Makefile.am b/source/hotspotfd/Makefile.am index 8e1f70a..fc5321d 100644 --- a/source/hotspotfd/Makefile.am +++ b/source/hotspotfd/Makefile.am @@ -32,4 +32,6 @@ CcspHotspot_SOURCES = hotspotfd.c dhcpsnooper.c ssp_messagebus_interface.c ssp_m if FEATURE_WAN_FAIL_OVER AM_CFLAGS += -DWAN_FAILOVER_SUPPORTED endif +AM_CFLAGS += -I${PKG_CONFIG_SYSROOT_DIR}$(includedir)/rbus +AM_LDFLAGS += -lrbus CcspHotspot_LDADD = ${top_builddir}/source/HotspotApi/libHotspotApi.la diff --git a/source/hotspotfd/cosa_hotspot_dml.c b/source/hotspotfd/cosa_hotspot_dml.c index 8e804aa..1631ecd 100644 --- a/source/hotspotfd/cosa_hotspot_dml.c +++ b/source/hotspotfd/cosa_hotspot_dml.c @@ -143,7 +143,7 @@ BOOL HotspotConnectedDevice_SetParamStringValue(ANSC_HANDLE hInsContext, char* P { CcspTraceInfo(("Added case, Client with MAC:%s will be added\n", l_cMacAddr)); t2_event_d("WIFI_INFO_Hotspot_client_connected", 1); - updateRssiForClient(l_cMacAddr, l_iRssi); + updateRssiForClient(l_cMacAddr, l_iRssi, l_iSsidIndex); } else { diff --git a/source/hotspotfd/dhcpsnooper.c b/source/hotspotfd/dhcpsnooper.c index c24735e..e7bbeea 100644 --- a/source/hotspotfd/dhcpsnooper.c +++ b/source/hotspotfd/dhcpsnooper.c @@ -55,6 +55,8 @@ #include #include "safec_lib_common.h" #include "libHotspot.h" +#include +#include #define mylist_safe(p, q, h) \ @@ -133,6 +135,8 @@ static char g_cHostnameForQueue[kSnoop_MaxCircuitIDs][kSnooper_MaxHostNameLen]; static char g_cInformIpForQueue[kSnoop_MaxCircuitIDs][INET_ADDRSTRLEN]; extern vlanSyncData_s gVlanSyncData[]; extern int gVlanSyncDataSize; +client_node_t *client_list = NULL; +extern rbusHandle_t disassoc_rbus_handle; #if 0 static void snoop_setDhcpRelayAgentAddAgentOptions(int aao) @@ -155,6 +159,119 @@ static enum agent_relay_mode_t snoop_getDhcpRelayAgentMode( ) return agent_relay_mode; } #endif + +int publishToOneWifi(char *cmdStr) +{ + rbusError_t rc = RBUS_ERROR_SUCCESS; + rbusValue_t value; + + msg_debug("Command string: %s - %s\n", cmdStr, __FUNCTION__); + + if (cmdStr == NULL || strlen(cmdStr) == 0) { + msg_debug("mac address empty and not sending rbus event to onewifi: %d\n", __LINE__); + return 0; + } + + // Initialize RBus value + rbusValue_Init(&value); + rbusValue_SetString(value, cmdStr); + + // Set property using RBus + rc = rbus_set(disassoc_rbus_handle, "Device.X_COMCAST-COM_GRE.Hotspot.RejectAssociatedClient", value, NULL); + + // Clean up + rbusValue_Release(value); + + if (rc != RBUS_ERROR_SUCCESS) { + msg_debug("Failed to set RBus property: error code %d (line %d)\n", rc, __LINE__); + return 0; + } + + msg_debug("Successfully published to OneWifi via RBus\n"); + return 1; +} + +dhcp_client_state_t* get_client_state(const char *mac) +{ + if (mac == NULL || strlen(mac) == 0) { + msg_debug("get_client_state: Invalid MAC address input\n"); + return NULL; + } + + client_node_t *cur = client_list; + while (cur) { + if (strcmp(cur->mac, mac) == 0) + return &cur->state; + cur = cur->next; + } + + // Not found, create new + client_node_t *new_node = (client_node_t *)calloc(1, sizeof(client_node_t)); + if (!new_node) { + msg_debug("get_client_state: Memory allocation failed for MAC %s\n", mac); + return NULL; + } + strncpy(new_node->mac, mac, sizeof(new_node->mac) - 1); + msg_debug("new_node->mac: %s\n", new_node->mac); + new_node->mac[sizeof(new_node->mac) - 1] = '\0'; + new_node->next = client_list; + client_list = new_node; + return &new_node->state; +} + +// Remove client node from the linked list by MAC address +void remove_client_state(const char *mac) +{ + if (!mac || !client_list) + return; + client_node_t *prev = NULL, *cur = client_list; + while (cur) + { + if (strcmp(cur->mac, mac) == 0) + { + if (prev) + { + prev->next = cur->next; + } + else + { + client_list = cur->next; + } + free(cur); + return; + } + prev = cur; + cur = cur->next; + } +} + +static void constructCommand(char *macaddr, char *cmd) +{ + snooper_priv_client_list * pNewClient; + struct mylist_head * pos, * q; + bool already_in_list = false; + char macaddrWithIndex[64] = {0}; + pthread_mutex_lock(&global_stats_mutex); + mylist_safe(pos, q, &gSnoop_ClientList.list) { + + pNewClient= mylist_entry(pos, snooper_priv_client_list, list); + if(!strcasecmp(pNewClient->client.remote_id, macaddr)) { + already_in_list = true; + break; + } + } + if(already_in_list) + { + msg_debug("Client:%s is present in list\n", macaddr); + sprintf(macaddrWithIndex, "%s_%d", macaddr, pNewClient->client.vapIndex); + macaddrWithIndex[sizeof(macaddrWithIndex) - 1] = '\0'; + } + strncpy(cmd, macaddrWithIndex, sizeof(macaddrWithIndex) - 1); + msg_debug("constructCommand :%s\n", cmd); + pthread_mutex_unlock(&global_stats_mutex); + +} + #if defined (AMENITIES_NETWORK_ENABLED) static BOOL isValidAmenityQueue(int queue_number, int *pIndex) { @@ -740,7 +857,7 @@ static void snoop_CheckClientIsPrivate(char *pRemote_id) } static void snoop_AddClientListEntry(char *pRemote_id, char *pCircuit_id, - char *pDhcp_status, char *pIpv4_addr, char *pHostname, int rssi) + char *pDhcp_status, char *pIpv4_addr, char *pHostname, int rssi,int vap_index) { errno_t rc = -1; snooper_priv_client_list * pNewClient; @@ -820,6 +937,7 @@ static void snoop_AddClientListEntry(char *pRemote_id, char *pCircuit_id, } } pNewClient->client.rssi = rssi; + pNewClient->client.vapIndex = vap_index; pNewClient->client.noOfTriesForOnlineCheck = 0; mylist_add(&pNewClient->list, &gSnoop_ClientList.list); gSnoopNumberOfClients++; @@ -870,7 +988,8 @@ static void snoop_AddClientListEntry(char *pRemote_id, char *pCircuit_id, } else { - pNewClient->client.rssi = rssi; + pNewClient->client.rssi = rssi; + pNewClient->client.vapIndex = vap_index; } } mutex_cleanup: @@ -1005,6 +1124,13 @@ static bool snoop_isValidIpAddress(char *ipAddress) return (result != 0 && sa.sin_addr.s_addr != 0); } +// Function to calculate the elapsed time in milliseconds +static long calculate_elapsed_time(struct timespec start) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return (now.tv_sec - start.tv_sec) * 1000 + (now.tv_nsec - start.tv_nsec) / 1000000; +} + static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *msg,struct nfq_data *pkt, void *cbData) { UNREFERENCED_PARAMETER(msg); @@ -1021,6 +1147,7 @@ static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *m struct iphdr *iph = NULL; /* Coverity Fix CID: 74885 UnInit var */ char ipv4_addr[INET_ADDRSTRLEN] = {0}; + char madaddrwithIndex[64] = {0}; // The iptables queue number is passed when this handler is registered // with nfq_create_queue @@ -1082,6 +1209,32 @@ static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *m } } + char mac_str[18]; + snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", + pktData[56], pktData[57], pktData[58], pktData[59], pktData[60], pktData[61]); + dhcp_client_state_t *state = get_client_state(mac_str); + if (!state) + { + msg_debug("Failed to create client state for MAC %s\n", mac_str); + } + + // Check if the timer has exceeded 10 seconds + if (state->timer_running) { + long elapsed_time = calculate_elapsed_time(state->dhcp_timer_start); + if (elapsed_time >= 3000) { // 10 seconds + if (!(state->dhcp_discover && state->dhcp_request && state->dhcp_offer && state->dhcp_ack)) { + constructCommand(mac_str, madaddrwithIndex); + if(publishToOneWifi(madaddrwithIndex)) + { + msg_debug("DHCP ACK not received for client MAC.Publising RBus event Timer stopped. Time elapsed: %ld s - line %d\n", + (elapsed_time/1000), __LINE__); + } + } + state->timer_running = false; + state->dhcp_discover = state->dhcp_request = state->dhcp_offer = state->dhcp_ack = false; // Reset for next session + remove_client_state(mac_str); + } + } // If gSnoopEnable is not set then just send the packet out if (((pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Request) || (pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Discover) || (pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Decline) || (pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Release) || (pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Inform)) @@ -1099,6 +1252,25 @@ static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *m } else #endif + + if(pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Discover) + { + msg_debug("%s:%d> DHCP Discover\n", __FUNCTION__, __LINE__); + if (!state->timer_running) { + clock_gettime(CLOCK_MONOTONIC, &state->dhcp_timer_start); + state->timer_running = true; + state->ipv4_addr[0] = '\0'; + state->dhcp_discover = true; + state->dhcp_request = false; + state->dhcp_offer = false; + state->dhcp_ack = false; + } + } + if(pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Request) + { + msg_debug("%s:%d> DHCP Request\n", __FUNCTION__, __LINE__); + state->dhcp_request = true; + } rc = strcpy_s(gCircuit_id, sizeof(gCircuit_id), gSnoopCircuitIDList[queue_number]); if(rc != EOK) { @@ -1209,6 +1381,28 @@ static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *m if ( (pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Offer) || (pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_ACK)) { + if(pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_Offer) + { + msg_debug("%s:%d> DHCP Offer\n", __FUNCTION__, __LINE__); + state->dhcp_offer = true; + } + else if(pktData[kSnoop_DHCP_Option53_Offset] == kSnoop_DHCP_ACK) + { + msg_debug("%s:%d> DHCP ACK\n", __FUNCTION__, __LINE__); + memset(state->ipv4_addr, 0, sizeof(state->ipv4_addr)); + inet_ntop(AF_INET, &(pktData[44]), state->ipv4_addr, INET_ADDRSTRLEN); + if (strcmp(state->ipv4_addr, "172.20.20.20") == 0) { + state->dhcp_ack = true; + } + } + if (state->timer_running && state->dhcp_discover && state->dhcp_request && state->dhcp_offer && state->dhcp_ack) + { + long elapsed_time = calculate_elapsed_time(state->dhcp_timer_start); + msg_debug("All DHCP states completed with ACK IP 172.20.20.20 in %ld ms. Timer stopped.\n", elapsed_time); + state->timer_running = false; + state->dhcp_discover = state->dhcp_request = state->dhcp_offer = state->dhcp_ack = false; + remove_client_state(mac_str); + } msg_debug("%s:%d> DHCP Offer / DHCP Ack:%d received from server \n", __FUNCTION__, __LINE__, pktData[kSnoop_DHCP_Option53_Offset]); new_data_len = snoop_removeRelayAgentOptions((struct dhcp_packet *)&pktData[kSnoop_DHCP_Options_Start], len, queue_number); @@ -1335,7 +1529,7 @@ static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *m ERR_CHK(rc); return -1; } - snoop_AddClientListEntry(gRemote_id, gCircuit_id, "ACK", ipv4_addr, l_cHostName, 0); + snoop_AddClientListEntry(gRemote_id, gCircuit_id, "ACK", ipv4_addr, l_cHostName, 0,0); snoop_CheckClientIsPrivate(gRemote_id); } snoop_log(); @@ -1350,7 +1544,7 @@ static int snoop_packetHandler(struct nfq_q_handle * myQueue, struct nfgenmsg *m } } -void updateRssiForClient(char* pRemote_id, int rssi) +void updateRssiForClient(char* pRemote_id, int rssi,int vap_index) { bool already_in_list = false; struct mylist_head * pos, * q; @@ -1363,6 +1557,7 @@ void updateRssiForClient(char* pRemote_id, int rssi) if(!strcasecmp(pNewClient->client.remote_id, pRemote_id)) { already_in_list = true; pNewClient->client.rssi = rssi; + pNewClient->client.vapIndex = vap_index; break; } } @@ -1370,7 +1565,7 @@ void updateRssiForClient(char* pRemote_id, int rssi) if (false == already_in_list) { msg_debug("Client :%s is not present Add to the clientlist\n", pRemote_id); - snoop_AddClientListEntry(pRemote_id, NULL, NULL, NULL, NULL, rssi); + snoop_AddClientListEntry(pRemote_id, NULL, NULL, NULL, NULL, rssi,vap_index); } else { diff --git a/source/hotspotfd/hotspotfd.c b/source/hotspotfd/hotspotfd.c index ad99c54..c2f93e1 100644 --- a/source/hotspotfd/hotspotfd.c +++ b/source/hotspotfd/hotspotfd.c @@ -191,6 +191,11 @@ STATIC pthread_t rbus_tid; #endif rbusHandle_t handle; +#define HOTSPOT_NUM_OF_RBUS_PARAMS sizeof(hotspotRbusDataElements)/sizeof(hotspotRbusDataElements[0]) +#define HIPADDR "Device.X_COMCAST-COM_GRE.Hotspot.RejectAssociatedClient" +static rbusError_t rbus_privateIPAddr_SetStringHandler(rbusHandle_t handle, rbusProperty_t prop, rbusSetHandlerOptions_t* opts); +rbusHandle_t disassoc_rbus_handle; + STATIC pthread_t dhcp_snooper_tid; char TunnelStatus[8] = {0}; @@ -279,6 +284,70 @@ Hotspotfd_MsgItem hotspotfdMsgArr[] = { {"test_current_wan_ifname", TEST_CURRENT_WAN_IFNAME} #endif }; + + rbusDataElement_t hotspotRbusDataElements[] = + { + /* RBUS_BOOLEAN */ + {HIPADDR, RBUS_ELEMENT_TYPE_PROPERTY, {NULL, rbus_privateIPAddr_SetStringHandler, NULL, NULL, NULL, NULL}} + }; + +void dhcpClientPrivateIpAddressPublish( char* eventData) +{ + rbusValue_t value; + rbusObject_t rd; + char eventName[64] = {0}; + + rbusValue_Init(&value); + rbusObject_Init(&rd, NULL); + + snprintf(eventName, 64, "%s",HIPADDR); + rbusValue_SetString(value, eventData); + + rbusObject_SetValue(rd, eventName, value); + + rbusEvent_t event; + event.name = eventName; + event.data = rd; + event.type = RBUS_EVENT_GENERAL; + + int rc = rbusEvent_Publish(disassoc_rbus_handle, &event); + if(rc != RBUS_ERROR_SUCCESS){ + if (rc == RBUS_ERROR_NOSUBSCRIBERS) { + CcspTraceInfo(("%s: No subscribers found\n", __FUNCTION__)); + } + CcspTraceInfo(("%s:%d rbusEvent_Publish %s failed\n", __func__, __LINE__, event.name )); + } + rbusValue_Release(value); + rbusObject_Release(rd); +} + +/** + * @brief RBUS-compliant wrapper for setting the private IP address. + * This function has the correct signature for an rbus setHandler. + */ +static rbusError_t rbus_privateIPAddr_SetStringHandler(rbusHandle_t handle, rbusProperty_t prop, rbusSetHandlerOptions_t* opts) +{ + UNREFERENCED_PARAMETER(handle); + UNREFERENCED_PARAMETER(opts); + + char const* propName = rbusProperty_GetName(prop); + rbusValue_t value = rbusProperty_GetValue(prop); + char const* str_val = rbusValue_GetString(value, NULL); + + if (!str_val) + { + CcspTraceWarning(("%s: Received NULL value for property %s\n", __FUNCTION__, propName)); + return RBUS_ERROR_INVALID_INPUT; + } + + CcspTraceInfo(("%s: Calling original handler for %s with value %s\n", __FUNCTION__, propName, str_val)); + + /* Call the original logic, which now correctly handles the void return */ + // privateIPAddr_SetStringHandler(NULL, (char*)propName, (char*)str_val); + dhcpClientPrivateIpAddressPublish((char*)str_val); + + return RBUS_ERROR_SUCCESS; +} HotspotfdType Get_HotspotfdType(char * name) { @@ -2009,6 +2078,35 @@ void *handle_rbusSubscribe() { } #endif +//Initialize rbus for Dissociation of private client parameter +rbusError_t hotspotDisassocClientRbusInit() +{ + int rc = RBUS_ERROR_SUCCESS; + if(RBUS_ENABLED != rbus_checkStatus()) + { + CcspTraceWarning(("%s: RBUS not available. Events are not supported\n", __FUNCTION__)); + return RBUS_ERROR_BUS_ERROR; + } + + rc = rbus_open(&disassoc_rbus_handle, "HotSpotPrivateClientDisable"); + if (rc != RBUS_ERROR_SUCCESS) + { + CcspTraceWarning(("CMAgent rbus initialization failed\n")); + rc = RBUS_ERROR_NOT_INITIALIZED; + return rc; + } + + // Register data elements + rc = rbus_regDataElements(disassoc_rbus_handle, HOTSPOT_NUM_OF_RBUS_PARAMS, hotspotRbusDataElements); + if (rc != RBUS_ERROR_SUCCESS) + { + CcspTraceError(("rbus register data elements failed\n")); + rc = rbus_close(disassoc_rbus_handle); + return rc; + } + return rc; +} + void hotspot_start() { unsigned int keepAliveThreshold = 0; @@ -2064,6 +2162,7 @@ void hotspot_start() v_secure_system("touch /tmp/hotspotfd_up"); hotspotfd_log(); + hotspotDisassocClientRbusInit(); rbusDataElement_t dataElements[1] = { {"Device.X_COMCAST-COM_GRE.Tunnel.1.TunnelStatus", RBUS_ELEMENT_TYPE_EVENT | RBUS_ELEMENT_TYPE_PROPERTY, {TunnelStatus_GetStringHandler, TunnelStatus_SetStringHandler, NULL, NULL, TunnelStatus_EventSubHandler, NULL}} diff --git a/source/hotspotfd/include/dhcpsnooper.h b/source/hotspotfd/include/dhcpsnooper.h index 6570c47..a465828 100644 --- a/source/hotspotfd/include/dhcpsnooper.h +++ b/source/hotspotfd/include/dhcpsnooper.h @@ -188,6 +188,7 @@ typedef struct char dhcp_status[kSnooper_MaxStatusLen]; char hostname[kSnooper_MaxHostNameLen]; int rssi; + int vapIndex; int noOfTriesForOnlineCheck; } snooper_client_list; @@ -222,12 +223,28 @@ typedef struct } snooper_statistics_s; +typedef struct { + struct timespec dhcp_timer_start; + bool timer_running; + bool dhcp_discover; + bool dhcp_request; + bool dhcp_offer; + bool dhcp_ack; + char ipv4_addr[INET_ADDRSTRLEN]; +} dhcp_client_state_t; + +typedef struct client_node { + char mac[18]; + dhcp_client_state_t state; + struct client_node *next; +} client_node_t; + #define kSnooper_Statistics 865889 // key used for shared memory #define kSnooper_SharedMemSize sizeof(snooper_statistics_s) #define DNSMASQ_LEASES_FILE "/nvram/dnsmasq.leases" void *dhcp_snooper_init(void *); -void updateRssiForClient(char* pRemote_id, int rssi); +void updateRssiForClient(char* pRemote_id, int rssi,int vap_index); void snoop_RemoveClientListEntry(char *pRemote_id); uint16_t snoop_ipChecksum(struct iphdr * header); void snoop_log(void);