/***************************************************************************/ /** * @file * @brief ******************************************************************************* * # License * Copyright 2024 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #include "sl_si91x_host_interface.h" #include "sl_si91x_types.h" #include "sl_si91x_protocol_types.h" #include "sl_si91x_driver.h" #include "sl_wifi_constants.h" #include "sl_wifi_types.h" #include "sl_rsi_utility.h" #include "cmsis_os2.h" #include "cmsis_compiler.h" #include "sl_si91x_core_utilities.h" #include #ifdef SLI_SI91X_MCU_INTERFACE #include "rsi_m4.h" #endif #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK #include "sl_si91x_socket_types.h" #include "sl_si91x_socket_utility.h" #include "sl_net_si91x_integration_handler.h" #else // This macro defines a handler for dispatching network events. // It is used to handle events related to the SI91x module #define SL_NET_EVENT_DISPATCH_HANDLER(data, packet) \ { \ UNUSED_PARAMETER(data); \ UNUSED_PARAMETER(packet); \ } #endif #ifdef SLI_SI91X_ENABLE_BLE #include "rsi_bt_common.h" #endif #define BUS_THREAD_EVENTS \ (SL_SI91X_ALL_TX_PENDING_COMMAND_EVENTS | SL_SI91X_SOCKET_DATA_TX_PENDING_EVENT | SL_SI91X_NCP_HOST_BUS_RX_EVENT \ | SL_SI91X_SOCKET_COMMAND_TX_PENDING_EVENT | SL_SI91X_GENERIC_DATA_TX_PENDING_EVENT \ | SL_SI91X_TA_BUFFER_FULL_CLEAR_EVENT | SL_SI91X_TERMINATE_BUS_THREAD_EVENT) /** * All flags used with async events */ #define SL_SI91X_NOTIFICATION_FLAG(x) (1 << (x)) // Indicates asynchronous RX response received for WLAN command type #define NCP_HOST_WLAN_NOTIFICATION_EVENT SL_SI91X_NOTIFICATION_FLAG(SI91X_WLAN_CMD) // Indicates asynchronous RX response received for NETWORK command type #define NCP_HOST_NETWORK_NOTIFICATION_EVENT SL_SI91X_NOTIFICATION_FLAG(SI91X_NETWORK_CMD) // Indicates asynchronous RX response received for SOCKET command type #define NCP_HOST_SOCKET_NOTIFICATION_EVENT SL_SI91X_NOTIFICATION_FLAG(SI91X_SOCKET_CMD) // Indicates asynchronous RX response received for SOCKET data type #define NCP_HOST_SOCKET_DATA_NOTIFICATION_EVENT SL_SI91X_NOTIFICATION_FLAG(SI91X_CMD_MAX) /****************************************************** * Variable Definitions ******************************************************/ extern osEventFlagsId_t si91x_async_events; extern osEventFlagsId_t si91x_events; volatile uint32_t tx_command_queues_status = 0; volatile uint32_t tx_socket_command_queues_status = 0; volatile uint32_t tx_socket_data_queues_status = 0; volatile uint32_t tx_generic_socket_data_queues_status = 0; volatile uint32_t tx_command_queues_command_in_flight_status = 0; volatile uint8_t tx_socket_command_command_in_flight_queues_status = 0; #if SLI_SI91X_MCU_INTERFACE extern sl_si91x_buffer_queue_t sli_ahb_bus_rx_queue; #endif #if SL_NCP_UART_INTERFACE extern sl_si91x_buffer_queue_t sli_uart_bus_rx_queue; #endif /****************************************************** * Function Declarations ******************************************************/ void si91x_event_handler_thread(const void *args); static void set_async_event(uint32_t event_mask); // Declaration of a global flag to indicate if background mode is enabled extern bool bg_enabled; // Declaration of the SI91x event handler function extern sl_wifi_event_handler_t si91x_event_handler; extern sli_si91x_command_queue_t cmd_queues[SI91X_CMD_MAX]; extern sl_si91x_buffer_queue_t sli_tx_data_queue; void si91x_event_handler_thread(const void *args); extern sl_status_t sl_create_generic_rx_packet_from_params(sli_si91x_queue_packet_t **queue_packet, sl_wifi_buffer_t **packet_buffer, uint16_t packet_id, uint8_t flags, void *sdk_context, uint16_t frame_status); void sli_submit_rx_buffer(void); void si91x_bus_thread(const void *args); void sli_handle_dhcp_and_rejoin_failure(void *sdk_context, sl_wifi_buffer_t *temp_buffer, uint16_t frame_status); void si91x_event_handler_thread(const void *args); #ifdef SLI_SI91X_MCU_INTERFACE // External declaration of a function to configure M4 DMA descriptors on reset extern void sli_si91x_config_m4_dma_desc_on_reset(void); void unmask_ta_interrupt(uint32_t interrupt_no); #endif static sl_status_t bus_write_data_frame(sl_si91x_buffer_queue_t *queue); static sl_status_t bus_write_frame(sli_si91x_command_queue_t *queue, sl_si91x_command_type_t command_type, sl_wifi_buffer_type_t buffer_type, bool *global_queue_block); sl_status_t si91x_req_wakeup(void); #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK static sli_si91x_socket_t *get_socket_from_packet(sl_si91x_packet_t *socket_packet); #endif bool sli_si91x_is_bus_ready(bool global_queue_block); /****************************************************** * Function Definitions ******************************************************/ sl_status_t sl_create_generic_rx_packet_from_params(sli_si91x_queue_packet_t **queue_packet, sl_wifi_buffer_t **packet_buffer, uint16_t packet_id, uint8_t flags, void *sdk_context, uint16_t frame_status) { sli_si91x_queue_packet_t *packet = NULL; sl_wifi_buffer_t *buffer = NULL; sl_status_t status = SL_STATUS_OK; uint16_t temp = 0; status = sl_si91x_host_allocate_buffer(&buffer, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } *packet_buffer = buffer; packet = sl_si91x_host_get_buffer_data(buffer, 0, &temp); if (packet == NULL) { return SL_STATUS_NOT_AVAILABLE; } // Fill dummy packet with details passed buffer->id = packet_id; packet->sdk_context = sdk_context; packet->flags = flags; packet->frame_status = frame_status; packet->firmware_queue_id = RSI_WLAN_MGMT_Q; *queue_packet = packet; return SL_STATUS_OK; } void sli_handle_dhcp_and_rejoin_failure(void *sdk_context, sl_wifi_buffer_t *response_buffer, uint16_t frame_status) { sl_status_t status; sl_wifi_buffer_t *temp_buffer = NULL; sli_si91x_queue_packet_t *node; // Retrieve the packet data from the response buffer sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(response_buffer, 0, NULL); // Check for remote Wi-Fi client disconnection in concurrent mode if (packet->command == RSI_WLAN_RSP_CLIENT_DISCONNECTED && (get_opermode() == SL_SI91X_CONCURRENT_MODE)) { packet->desc[7] = SL_SI91X_WIFI_AP_VAP_ID; // Set the AP VAP ID } // Create a generic RX packet from the parameters status = sl_create_generic_rx_packet_from_params(&node, &temp_buffer, 0, 0, NULL, frame_status); if (status != SL_STATUS_OK) { return; // Exit if packet creation fails } sl_wifi_buffer_t *dummy_packet_buffer = NULL; // Allocate buffer for the dummy packet status = sl_si91x_host_allocate_buffer(&dummy_packet_buffer, SL_WIFI_RX_FRAME_BUFFER, (sizeof(packet->desc) + packet->length), SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME); if (status != SL_STATUS_OK) { sl_si91x_host_free_buffer(temp_buffer); // Free temp buffer on failure return; // Exit if buffer allocation fails } // Get the dummy packet data from the allocated buffer sl_si91x_packet_t *dummy_packet = sl_si91x_host_get_buffer_data(dummy_packet_buffer, 0, NULL); node->host_packet = dummy_packet_buffer; // Link dummy packet to the node node->sdk_context = sdk_context; // Copy the original packet data to the dummy packet memcpy(dummy_packet, packet, (sizeof(packet->desc) + packet->length)); // Enqueue the node packet and trigger the async event sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, temp_buffer); set_async_event(NCP_HOST_NETWORK_NOTIFICATION_EVENT); } // Weak implementation of the function to process data frames received from the SI91x module __WEAK sl_status_t sl_si91x_host_process_data_frame(sl_wifi_interface_t interface, sl_wifi_buffer_t *buffer) { UNUSED_PARAMETER(interface); UNUSED_PARAMETER(buffer); return SL_STATUS_OK; } /// Thread which handles the notification events. void si91x_event_handler_thread(const void *args) { UNUSED_PARAMETER(args); sl_wifi_event_t wifi_event = 0; uint32_t event = 0; sl_wifi_buffer_t *buffer = NULL; sl_si91x_packet_t *packet = NULL; sli_si91x_queue_packet_t *data = NULL; uint16_t frame_status = 0; const uint32_t event_mask = (NCP_HOST_WLAN_NOTIFICATION_EVENT | NCP_HOST_NETWORK_NOTIFICATION_EVENT | NCP_HOST_SOCKET_NOTIFICATION_EVENT | NCP_HOST_SOCKET_DATA_NOTIFICATION_EVENT); while (1) { event = osEventFlagsWait(si91x_async_events, event_mask, osFlagsWaitAny, osWaitForever); // event = si91x_host_wait_for_async_event(event_mask, osWaitForever); if ((event & NCP_HOST_WLAN_NOTIFICATION_EVENT) != 0) { // Process WLAN notification events while (sl_si91x_host_queue_status(&cmd_queues[SI91X_WLAN_CMD].event_queue) != 0) { if (sli_si91x_remove_from_queue(&cmd_queues[SI91X_WLAN_CMD].event_queue, &buffer) == SL_STATUS_OK) { packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL); frame_status = get_si91x_frame_status(packet); // Call event handler if (si91x_event_handler != NULL) { wifi_event = convert_si91x_event_to_sl_wifi_event(packet->command, frame_status); if (RSI_WLAN_RSP_SCAN_RESULTS == packet->command) { sli_handle_wifi_beacon(packet); } if (wifi_event != SL_WIFI_INVALID_EVENT) { si91x_event_handler(wifi_event, buffer); } } else { // TODO: error handling } sl_si91x_host_free_buffer(buffer); } } } // If firmware sends network events even if the sl_net component is not include // (probably firmware issue), Free the resources of the packet to avoid memory leak if ((event & NCP_HOST_NETWORK_NOTIFICATION_EVENT) != 0) { while (sl_si91x_host_queue_status(&cmd_queues[SI91X_NETWORK_CMD].event_queue) != 0) { if (sli_si91x_remove_from_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, &buffer) == SL_STATUS_OK) { data = (sli_si91x_queue_packet_t *)sl_si91x_host_get_buffer_data(buffer, 0, NULL); packet = (sl_si91x_packet_t *)sl_si91x_host_get_buffer_data(data->host_packet, 0, NULL); SL_NET_EVENT_DISPATCH_HANDLER(data, packet); // Free the resources associated with the packet. sl_si91x_host_free_buffer(data->host_packet); sl_si91x_host_free_buffer(buffer); } else { // TODO: error handling } } } // Process socket notification events if ((event & NCP_HOST_SOCKET_NOTIFICATION_EVENT) != 0) { while (0 != sl_si91x_host_queue_status(&cmd_queues[SI91X_SOCKET_CMD].event_queue)) { if (sli_si91x_remove_from_queue(&cmd_queues[SI91X_SOCKET_CMD].event_queue, &buffer) == SL_STATUS_OK) { data = (sli_si91x_queue_packet_t *)sl_si91x_host_get_buffer_data(buffer, 0, NULL); packet = (sl_si91x_packet_t *)sl_si91x_host_get_buffer_data(data->host_packet, 0, NULL); SL_NET_EVENT_DISPATCH_HANDLER(data, packet); // Free the resources associated with the packet sl_si91x_host_free_buffer(data->host_packet); sl_si91x_host_free_buffer(buffer); } else { // TODO: error handling } } } #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK // Process socket data events if (event & NCP_HOST_SOCKET_DATA_NOTIFICATION_EVENT) { for (int i = 0; i < NUMBER_OF_SOCKETS; ++i) { if (sli_si91x_sockets[i] != NULL) { if (sli_si91x_remove_from_queue(&sli_si91x_sockets[i]->rx_data_queue, &buffer) == SL_STATUS_OK) { if (sli_si91x_sockets[i]->recv_data_callback != NULL) { packet = (sl_si91x_packet_t *)sl_si91x_host_get_buffer_data(buffer, 0, NULL); sl_si91x_socket_metadata_t *receive_data = (sl_si91x_socket_metadata_t *)packet->data; sli_si91x_sockets[i]->recv_data_callback(i, &packet->data[receive_data->offset], receive_data->length, receive_data); } sl_si91x_host_free_buffer(buffer); } } } } #endif } } // Thread which handles the TX and RX events. void si91x_bus_thread(const void *args) { UNUSED_PARAMETER(args); sl_status_t status; uint16_t temp; sli_si91x_queue_packet_t *node = NULL; sli_si91x_queue_packet_t *error_node = NULL; sl_wifi_buffer_t *packet; sl_wifi_buffer_t *error_packet = NULL; sl_wifi_buffer_t *buffer; uint8_t tx_queues_empty = 0; uint32_t event = 0; uint8_t *data; uint16_t length; uint8_t queue_id = 0; uint16_t frame_type = 0; uint16_t frame_status = 0; bool global_queue_block = false; uint16_t interrupt_status = 0; sl_wifi_performance_profile_t current_power_profile_mode = { 0 }; uint32_t bus_wait_time = 0; // Array to track the status of commands in flight cmd_queues[SI91X_COMMON_CMD].sequential = true; cmd_queues[SI91X_WLAN_CMD].sequential = true; cmd_queues[SI91X_NETWORK_CMD].sequential = true; cmd_queues[SI91X_BT_CMD].sequential = true; cmd_queues[SI91X_SOCKET_CMD].sequential = true; while (1) { // 0 - give up bus thread // 1 - need to process some tx commands/data packets tx_queues_empty = ( #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK (tx_socket_data_queues_status || (tx_socket_command_queues_status & (~(tx_socket_command_command_in_flight_queues_status)))) || #endif (tx_command_queues_status & (~(tx_command_queues_command_in_flight_status))) || tx_generic_socket_data_queues_status); // TODO: Add checking ALL socket command queues // Set wait time: // If there might be a buffer to receive, do that immediately, // If the last interrupt_status check indicates buffer full, wait up to 10ms, // If there is queue not empty or some event to be processed do that immediately, // Otherwise there is nothing left to do and thus wait for an event if (event & SL_SI91X_NCP_HOST_BUS_RX_EVENT) { bus_wait_time = 0; } else if (interrupt_status & RSI_BUFFER_FULL) { bus_wait_time = 10; } else if (tx_queues_empty == 0) { bus_wait_time = osWaitForever; } else { bus_wait_time = 0; } event |= si91x_host_wait_for_bus_event(BUS_THREAD_EVENTS, bus_wait_time); #ifndef SLI_SI91X_MCU_INTERFACE // Wake device, if needed if ((current_performance_profile != HIGH_PERFORMANCE)) { while (si91x_req_wakeup() != SL_STATUS_OK) { osDelay(1); } } // Read the interrupt status if (sl_si91x_bus_read_interrupt_status(&interrupt_status) != SL_STATUS_OK) { continue; } // Check if there is no RX packet pending or the bus RX event is not set if (!((interrupt_status & RSI_RX_PKT_PENDING) || (event & SL_SI91X_NCP_HOST_BUS_RX_EVENT))) { if (current_performance_profile != HIGH_PERFORMANCE) { // Clear the sleep indicator if the device is not in high-performance mode sl_si91x_host_clear_sleep_indicator(); } } #endif // Check if there is an RX packet pending or bus RX event is set if ((event & SL_SI91X_NCP_HOST_BUS_RX_EVENT) #ifndef SLI_SI91X_MCU_INTERFACE && (interrupt_status & RSI_RX_PKT_PENDING) #endif && (sl_si91x_bus_read_frame(&buffer) == SL_STATUS_OK)) { // Allocation from RX buffer type! if (current_performance_profile != HIGH_PERFORMANCE) { sl_si91x_host_clear_sleep_indicator(); } // Check if the rx queue is empty #ifdef SLI_SI91X_MCU_INTERFACE if (sli_si91x_buffer_queue_empty(&sli_ahb_bus_rx_queue)) { #else #ifdef SL_NCP_UART_INTERFACE if (sli_si91x_buffer_queue_empty(&sli_uart_bus_rx_queue)) { #else { #endif #endif event &= ~SL_SI91X_NCP_HOST_BUS_RX_EVENT; // Reset the event flag } data = (uint8_t *)sl_si91x_host_get_buffer_data(buffer, 0, &length); // Process the frame queue_id = ((data[1] & 0xF0) >> 4); // Extract the queue ID frame_type = (uint16_t)(data[2] + (data[3] << 8)); // Extract the frame type frame_status = (uint16_t)(data[12] + (data[13] << 8)); // Extract the frame status #ifdef SLI_SI91X_MCU_INTERFACE if ((frame_type == RSI_COMMON_RSP_TA_M4_COMMANDS) || (frame_type == RSI_WLAN_REQ_SET_CERTIFICATE)) { // clear flag sli_si91x_update_flash_command_status(false); } #endif const sl_si91x_packet_t *response = (const sl_si91x_packet_t *)data; SL_DEBUG_LOG("><<<< Rx -> queueId : %u, frameId : 0x%x, frameStatus: 0x%x, length : %u\n", queue_id, frame_type, frame_status, (response->length & (~(0xF000)))); switch (queue_id) { case RSI_WLAN_MGMT_Q: { // Erase queue ID as it overlays with the length field which is only 24-bit data[1] &= 0xF; switch (frame_type) { // Handle different frame types within the WLAN management queue case RSI_COMMON_RSP_OPERMODE: case RSI_COMMON_RSP_SOFT_RESET: case RSI_COMMON_RSP_PWRMODE: { if (frame_type == cmd_queues[SI91X_COMMON_CMD].frame_type) { if ((RSI_COMMON_RSP_PWRMODE == frame_type) && (frame_status == SL_STATUS_OK)) { get_wifi_current_performance_profile(¤t_power_profile_mode); current_performance_profile = current_power_profile_mode.profile; } if (current_performance_profile != HIGH_PERFORMANCE) { // Clear the sleep indicator if the device is not in high-performance mode sl_si91x_host_clear_sleep_indicator(); } global_queue_block = false; } } // intentional fallthrough __attribute__((fallthrough)); case RSI_COMMON_RSP_GET_EFUSE_DATA: case RSI_COMMON_RSP_GET_RAM_DUMP: case RSI_COMMON_RSP_ANTENNA_SELECT: case RSI_COMMON_RSP_ENCRYPT_CRYPTO: #ifdef SLI_PUF_ENABLE case RSI_COMMON_RSP_PUF_ENROLL: case RSI_COMMON_RSP_PUF_DIS_ENROLL: case RSI_COMMON_RSP_PUF_START: case RSI_COMMON_RSP_PUF_SET_KEY: case RSI_COMMON_RSP_PUF_DIS_SET_KEY: case RSI_COMMON_RSP_PUF_GET_KEY: case RSI_COMMON_RSP_PUF_DIS_GET_KEY: case RSI_COMMON_RSP_PUF_LOAD_KEY: case RSI_COMMON_RSP_AES_ENCRYPT: case RSI_COMMON_RSP_AES_DECRYPT: case RSI_COMMON_RSP_AES_MAC: case RSI_COMMON_RSP_PUF_INTR_KEY: #endif case RSI_COMMON_RSP_SET_RTC_TIMER: case RSI_COMMON_RSP_GET_RTC_TIMER: case RSI_COMMON_RSP_TA_M4_COMMANDS: case RSI_COMMON_RSP_SET_CONFIG: case RSI_COMMON_RSP_GET_CONFIG: case RSI_COMMON_RSP_DEBUG_LOG: case RSI_COMMON_RSP_FEATURE_FRAME: { ++cmd_queues[SI91X_COMMON_CMD].rx_counter; // Increment the received counter for common commands // Check if this command is expected to have a response status if (((cmd_queues[SI91X_COMMON_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) == SI91X_PACKET_RESPONSE_STATUS) && (cmd_queues[SI91X_COMMON_CMD].frame_type == frame_type)) { // Allocate a packet to store the response status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Depending on the configuration, attach the original buffer or not if (SI91X_PACKET_RESPONSE_PACKET == (cmd_queues[SI91X_COMMON_CMD].flags & SI91X_PACKET_RESPONSE_PACKET)) { node->host_packet = buffer; } else { node->host_packet = NULL; sl_si91x_host_free_buffer(buffer); } // Populate packet metadata node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_COMMON_CMD; node->sdk_context = cmd_queues[SI91X_COMMON_CMD].sdk_context; node->flags = cmd_queues[SI91X_COMMON_CMD].flags; // node->packet_id = cmd_queues[SI91X_COMMON_CMD].packet_id; buffer->id = cmd_queues[SI91X_COMMON_CMD].packet_id; packet->id = cmd_queues[SI91X_COMMON_CMD].packet_id; if (sl_si91x_host_elapsed_time(cmd_queues[SI91X_COMMON_CMD].command_tickcount) <= (cmd_queues[SI91X_COMMON_CMD].command_timeout)) { // Add the response packet to the common response queue sli_si91x_append_to_buffer_queue(&cmd_queues[SI91X_COMMON_CMD].rx_queue, packet); sli_si91x_set_event(NCP_HOST_COMMON_RESPONSE_EVENT); } else { // no user thread is waiting for the response so flush the packet sl_si91x_host_free_buffer(packet); if ((cmd_queues[SI91X_COMMON_CMD].flags & SI91X_PACKET_RESPONSE_PACKET) == SI91X_PACKET_RESPONSE_PACKET) { sl_si91x_host_free_buffer(buffer); } } cmd_queues[SI91X_COMMON_CMD].command_tickcount = 0; cmd_queues[SI91X_COMMON_CMD].command_timeout = 0; } else { sl_si91x_host_free_buffer(buffer); } // Marking a received frame as not in flight when it matches the expected type. if (frame_type == cmd_queues[SI91X_COMMON_CMD].frame_type) { cmd_queues[SI91X_COMMON_CMD].command_in_flight = false; cmd_queues[SI91X_COMMON_CMD].frame_type = 0; } break; } case RSI_WLAN_RSP_BAND: case RSI_WLAN_RSP_INIT: case RSI_WLAN_RSP_RADIO: case RSI_WLAN_RSP_EAP_CONFIG: case RSI_WLAN_RSP_SET_CERTIFICATE: case RSI_WLAN_RSP_HOST_PSK: case RSI_WLAN_RSP_JOIN: case RSI_WLAN_RSP_SCAN: case RSI_WLAN_RSP_SCAN_RESULTS: case RSI_WLAN_RSP_FW_VERSION: case RSI_WLAN_RSP_FULL_FW_VERSION: case RSI_WLAN_RSP_FWUP: case RSI_WLAN_RSP_DISCONNECT: case RSI_WLAN_RSP_AP_STOP: case RSI_WLAN_RSP_RSSI: case RSI_WLAN_RSP_TSF: case RSI_WLAN_RSP_AP_CONFIGURATION: case RSI_WLAN_RSP_WPS_METHOD: case RSI_WLAN_RSP_QUERY_NETWORK_PARAMS: case RSI_WLAN_RSP_SET_MAC_ADDRESS: case RSI_WLAN_RSP_SET_REGION: case RSI_WLAN_RSP_SET_REGION_AP: case RSI_WLAN_RSP_MAC_ADDRESS: case RSI_WLAN_RSP_EXT_STATS: case RSI_WLAN_RSP_GET_STATS: case RSI_WLAN_RSP_RX_STATS: case RSI_WLAN_RSP_MODULE_STATE: case RSI_WLAN_RSP_QUERY_GO_PARAMS: case RSI_WLAN_RSP_ROAM_PARAMS: case RSI_WLAN_RSP_HTTP_OTAF: case RSI_WLAN_RSP_CLIENT_CONNECTED: case RSI_WLAN_RSP_CLIENT_DISCONNECTED: case RSI_WLAN_RSP_CALIB_WRITE: case RSI_WLAN_RSP_GET_DPD_DATA: case RSI_WLAN_RSP_CALIB_READ: case RSI_WLAN_RSP_FREQ_OFFSET: case RSI_WLAN_RSP_EVM_OFFSET: case RSI_WLAN_RSP_EVM_WRITE: case RSI_WLAN_RSP_EFUSE_READ: case RSI_WLAN_RSP_FILTER_BCAST_PACKETS: case RSI_WLAN_RSP_TWT_PARAMS: case RSI_WLAN_RSP_TWT_ASYNC: case RSI_WLAN_RSP_TWT_AUTO_CONFIG: case RSI_WLAN_RSP_11AX_PARAMS: case SL_WIFI_RSP_RESCHEDULE_TWT: case RSI_WLAN_RSP_REJOIN_PARAMS: case RSI_WLAN_RSP_GAIN_TABLE: case RSI_WLAN_RSP_TX_TEST_MODE: case RSI_WLAN_RSP_TIMEOUT: case RSI_WLAN_RSP_BEACON_STOP: case RSI_WLAN_RSP_DYNAMIC_POOL: case RSI_WLAN_RSP_TRANSCEIVER_SET_CHANNEL: case RSI_WLAN_RSP_TRANSCEIVER_CONFIG_PARAMS: case RSI_WLAN_RSP_TRANSCEIVER_PEER_LIST_UPDATE: case RSI_WLAN_RSP_TRANSCEIVER_SET_MCAST_FILTER: case RSI_WLAN_RSP_TRANSCEIVER_FLUSH_DATA_Q: case RSI_WLAN_RSP_TRANSCEIVER_TX_DATA_STATUS: case RSI_WLAN_RSP_HT_CAPABILITIES: case RSI_WLAN_RSP_SET_MULTICAST_FILTER: { ++cmd_queues[SI91X_WLAN_CMD].rx_counter; // Marking a received frame as not in flight when it matches the expected type if (frame_type == cmd_queues[SI91X_WLAN_CMD].frame_type) { cmd_queues[SI91X_WLAN_CMD].command_in_flight = false; } // Check if the frame type indicates a failed join operation or a disconnect if (((RSI_WLAN_RSP_JOIN == frame_type) && (frame_status != SL_STATUS_OK)) || (RSI_WLAN_RSP_DISCONNECT == frame_type) || (RSI_WLAN_RSP_CLIENT_DISCONNECTED == frame_type) || (RSI_WLAN_RSP_AP_STOP == frame_type)) { // create dummy packets for respective queues to be cleared sli_handle_dhcp_and_rejoin_failure(cmd_queues[SI91X_WLAN_CMD].sdk_context, buffer, frame_status); } if (((RSI_WLAN_RSP_JOIN == frame_type) && (frame_status != SL_STATUS_OK)) || (RSI_WLAN_RSP_DISCONNECT == frame_type)) { // Reset current performance profile and set it to high performance reset_coex_current_performance_profile(); current_performance_profile = HIGH_PERFORMANCE; } // check if the frame type is valid if (((cmd_queues[SI91X_WLAN_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) == SI91X_PACKET_RESPONSE_STATUS) && (cmd_queues[SI91X_WLAN_CMD].frame_type == frame_type)) { // Allocate a buffer for the response packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Check if the packet response mode is set, and associate the host packet accordingly if (SI91X_PACKET_RESPONSE_PACKET == (cmd_queues[SI91X_WLAN_CMD].flags & SI91X_PACKET_RESPONSE_PACKET)) { node->host_packet = buffer; } else { node->host_packet = NULL; sl_si91x_host_free_buffer(buffer); } // Populate the response packet information node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_WLAN_CMD; node->sdk_context = cmd_queues[SI91X_WLAN_CMD].sdk_context; node->flags = cmd_queues[SI91X_WLAN_CMD].flags; // node->packet_id = cmd_queues[SI91X_WLAN_CMD].packet_id; packet->id = cmd_queues[SI91X_WLAN_CMD].packet_id; buffer->id = cmd_queues[SI91X_WLAN_CMD].packet_id; if (sl_si91x_host_elapsed_time(cmd_queues[SI91X_WLAN_CMD].command_tickcount) <= (cmd_queues[SI91X_WLAN_CMD].command_timeout)) { // Add the response packet to the WLAN response queue and set the WLAN response event sli_si91x_add_to_queue(&cmd_queues[SI91X_WLAN_CMD].rx_queue, packet); sli_si91x_set_event(NCP_HOST_WLAN_RESPONSE_EVENT); } else { // no user thread is waiting for the response so flush the packet sl_si91x_host_free_buffer(packet); if ((cmd_queues[SI91X_WLAN_CMD].flags & SI91X_PACKET_RESPONSE_PACKET) == SI91X_PACKET_RESPONSE_PACKET) { sl_si91x_host_free_buffer(buffer); } } cmd_queues[SI91X_WLAN_CMD].command_tickcount = 0; cmd_queues[SI91X_WLAN_CMD].command_timeout = 0; } else { // The received frame does not match the expected response status and frame type, // so add it to the WLAN event queue and set the WLAN notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_WLAN_CMD].event_queue, buffer); set_async_event(NCP_HOST_WLAN_NOTIFICATION_EVENT); } // Resetting the frame_type in cmd_queues when it matches the expected frame_type if (frame_type == cmd_queues[SI91X_WLAN_CMD].frame_type) { cmd_queues[SI91X_WLAN_CMD].frame_type = 0; } break; } // Handle WLAN response frame type for background scan case RSI_WLAN_RSP_BG_SCAN: { ++cmd_queues[SI91X_WLAN_CMD].rx_counter; // Check if the received frame matches the expected response status and frame type if (((cmd_queues[SI91X_WLAN_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) == SI91X_PACKET_RESPONSE_STATUS) && (cmd_queues[SI91X_WLAN_CMD].frame_type == frame_type)) { // Allocate a buffer for the response packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_WLAN_CMD; node->sdk_context = cmd_queues[SI91X_WLAN_CMD].sdk_context; node->flags = cmd_queues[SI91X_WLAN_CMD].flags; // node->packet_id = cmd_queues[SI91X_WLAN_CMD].packet_id; buffer->id = cmd_queues[SI91X_WLAN_CMD].packet_id; packet->id = cmd_queues[SI91X_WLAN_CMD].packet_id; node->host_packet = NULL; if (sl_si91x_host_elapsed_time(cmd_queues[SI91X_WLAN_CMD].command_tickcount) <= (cmd_queues[SI91X_WLAN_CMD].command_timeout)) { // Add the response packet to the WLAN response queue and set the WLAN response event sli_si91x_add_to_queue(&cmd_queues[SI91X_WLAN_CMD].rx_queue, packet); sli_si91x_set_event(NCP_HOST_WLAN_RESPONSE_EVENT); } else { // no user thread is waiting for the response so flush the packet and buffer sl_si91x_host_free_buffer(packet); } cmd_queues[SI91X_WLAN_CMD].command_tickcount = 0; cmd_queues[SI91X_WLAN_CMD].command_timeout = 0; sl_si91x_host_free_buffer(buffer); } else { // If frame status is OK, set bg_enabled flag if (frame_status == SL_STATUS_OK) { bg_enabled = true; } // Add the received frame to the WLAN event queue and set the WLAN notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_WLAN_CMD].event_queue, buffer); set_async_event(NCP_HOST_WLAN_NOTIFICATION_EVENT); } // Marking a received frame as not in flight when it matches the expected type if (frame_type == cmd_queues[SI91X_WLAN_CMD].frame_type) { cmd_queues[SI91X_WLAN_CMD].command_in_flight = false; cmd_queues[SI91X_WLAN_CMD].frame_type = 0; } break; } case RSI_WLAN_RSP_CONFIG: { ++cmd_queues[SI91X_WLAN_CMD].rx_counter; // Check if the received frame matches the expected response status and frame type if (((cmd_queues[SI91X_WLAN_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) == SI91X_PACKET_RESPONSE_STATUS) && (cmd_queues[SI91X_WLAN_CMD].frame_type == frame_type)) { // Allocate a buffer for the response packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Check if the frame status indicates an invalid configuration type if ((SL_STATUS_SI91X_INVALID_CONFIG_TYPE & 0xFF) == frame_status) { node->frame_status = 0; } else { node->frame_status = frame_status; } node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_WLAN_CMD; node->sdk_context = cmd_queues[SI91X_WLAN_CMD].sdk_context; node->flags = cmd_queues[SI91X_WLAN_CMD].flags; // node->packet_id = cmd_queues[SI91X_WLAN_CMD].packet_id; buffer->id = cmd_queues[SI91X_WLAN_CMD].packet_id; packet->id = cmd_queues[SI91X_WLAN_CMD].packet_id; node->host_packet = NULL; if (sl_si91x_host_elapsed_time(cmd_queues[SI91X_WLAN_CMD].command_tickcount) <= (cmd_queues[SI91X_WLAN_CMD].command_timeout)) { // Add the response packet to response queue and set the WLAN response event sli_si91x_add_to_queue(&cmd_queues[SI91X_WLAN_CMD].rx_queue, packet); sli_si91x_set_event(NCP_HOST_WLAN_RESPONSE_EVENT); } else { // no user thread is waiting for the response so flush the packet sl_si91x_host_free_buffer(packet); } cmd_queues[SI91X_WLAN_CMD].command_tickcount = 0; cmd_queues[SI91X_WLAN_CMD].command_timeout = 0; } // check if the frame type is valid. if (frame_type == cmd_queues[SI91X_WLAN_CMD].frame_type) { cmd_queues[SI91X_WLAN_CMD].command_in_flight = false; cmd_queues[SI91X_WLAN_CMD].frame_type = 0; } sl_si91x_host_free_buffer(buffer); break; } case RSI_COMMON_RSP_ULP_NO_RAM_RETENTION: { //This frame will come, when the M4 is waken in without ram retention. This frame is equivalent to RSI_COMMON_RSP_CARDREADY sl_si91x_host_clear_sleep_indicator(); } // intentional fallthrough __attribute__((fallthrough)); case RSI_COMMON_RSP_CARDREADY: { ++cmd_queues[SI91X_COMMON_CMD].rx_counter; // Check if the frame type is valid if (frame_type == cmd_queues[SI91X_COMMON_CMD].frame_type) { // Mark the common command as not in flight cmd_queues[SI91X_COMMON_CMD].command_in_flight = false; cmd_queues[SI91X_COMMON_CMD].frame_type = 0; cmd_queues[SI91X_COMMON_CMD].command_tickcount = 0; cmd_queues[SI91X_COMMON_CMD].command_timeout = 0; } sl_si91x_host_free_buffer(buffer); sli_si91x_set_event(NCP_HOST_COMMON_RESPONSE_EVENT); break; } case RSI_WLAN_RSP_IPCONFV4: case RSI_WLAN_RSP_IPCONFV6: case RSI_WLAN_RSP_IPV4_CHANGE: case RSI_WLAN_RSP_OTA_FWUP: case RSI_WLAN_RSP_DNS_QUERY: case RSI_WLAN_RSP_DNS_SERVER_ADD: case RSI_WLAN_RSP_SET_SNI_EMBEDDED: case RSI_WLAN_RSP_MULTICAST: case RSI_WLAN_RSP_PING_PACKET: case RSI_WLAN_RSP_SNTP_CLIENT: case RSI_WLAN_RSP_EMB_MQTT_CLIENT: case RSI_WLAN_RSP_EMB_MQTT_PUBLISH_PKT: case RSI_WLAN_RSP_MQTT_REMOTE_TERMINATE: case RSI_WLAN_RSP_MDNSD: { // Increment the received frame counter for network commands ++cmd_queues[SI91X_NETWORK_CMD].rx_counter; // Allocate a buffer for the response packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Set frame status, queue ID, and command type for the network response node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_NETWORK_CMD; // Check if the frame type is valid if ((frame_type == cmd_queues[SI91X_NETWORK_CMD].frame_type) || (frame_type == RSI_WLAN_RSP_IPCONFV6 && cmd_queues[SI91X_NETWORK_CMD].frame_type == RSI_WLAN_REQ_IPCONFV6)) { node->sdk_context = cmd_queues[SI91X_NETWORK_CMD].sdk_context; node->flags = cmd_queues[SI91X_NETWORK_CMD].flags; // node->packet_id = cmd_queues[SI91X_NETWORK_CMD].packet_id; packet->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; buffer->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; } else { node->sdk_context = NULL; node->flags = 0; // node->packet_id = 0; packet->id = 0; buffer->id = 0; } // Set the host packet to the received buffer node->host_packet = buffer; if (((frame_type == RSI_WLAN_RSP_MQTT_REMOTE_TERMINATE) || (frame_type == RSI_WLAN_RSP_EMB_MQTT_CLIENT && frame_status == (SL_STATUS_SI91X_MQTT_KEEP_ALIVE_TERMINATE_ERROR & ~BIT(16)))) && (cmd_queues[SI91X_NETWORK_CMD].frame_type == RSI_WLAN_RSP_EMB_MQTT_CLIENT)) { cmd_queues[SI91X_NETWORK_CMD].command_in_flight = false; cmd_queues[SI91X_NETWORK_CMD].frame_type = 0; if (cmd_queues[SI91X_NETWORK_CMD].flags == 0) { sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, packet); set_async_event(NCP_HOST_NETWORK_NOTIFICATION_EVENT); break; } // if command present in cmd_queues, an error RX packet is enqueued to network queue and command in flight is set to false. // Allocate a buffer for the error packet status = sl_si91x_host_allocate_buffer(&error_packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } error_node = sl_si91x_host_get_buffer_data(error_packet, 0, NULL); error_node->frame_status = (SL_STATUS_SI91X_MQTT_REMOTE_TERMINATE_ERROR & 0xFFFF); // error given by firmware for remote terminate error_node->host_packet = NULL; error_node->flags = cmd_queues[SI91X_NETWORK_CMD].flags; // error_node->packet_id = cmd_queues[SI91X_NETWORK_CMD].packet_id; error_packet->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].rx_queue, error_packet); sli_si91x_set_event(NCP_HOST_NETWORK_RESPONSE_EVENT); cmd_queues[SI91X_NETWORK_CMD].command_tickcount = 0; cmd_queues[SI91X_NETWORK_CMD].command_timeout = 0; break; } // Check if it's a response packet, and handle accordingly if (((cmd_queues[SI91X_NETWORK_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) == SI91X_PACKET_RESPONSE_STATUS) && ((cmd_queues[SI91X_NETWORK_CMD].frame_type == frame_type) || (cmd_queues[SI91X_NETWORK_CMD].frame_type == RSI_WLAN_REQ_IPCONFV6 && frame_type == RSI_WLAN_RSP_IPCONFV6))) { // Check if the response packet should be free or not if (SI91X_PACKET_RESPONSE_PACKET != (cmd_queues[SI91X_NETWORK_CMD].flags & SI91X_PACKET_RESPONSE_PACKET)) { node->host_packet = NULL; sl_si91x_host_free_buffer(buffer); } if (sl_si91x_host_elapsed_time(cmd_queues[SI91X_NETWORK_CMD].command_tickcount) <= (cmd_queues[SI91X_NETWORK_CMD].command_timeout)) { // Add the response packet to response queue and set the network response event sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].rx_queue, packet); sli_si91x_set_event(NCP_HOST_NETWORK_RESPONSE_EVENT); } else { // no user thread is waiting for the response so flush the packet sl_si91x_host_free_buffer(packet); if ((cmd_queues[SI91X_NETWORK_CMD].flags & SI91X_PACKET_RESPONSE_PACKET) == SI91X_PACKET_RESPONSE_PACKET) { sl_si91x_host_free_buffer(buffer); } } cmd_queues[SI91X_NETWORK_CMD].command_tickcount = 0; cmd_queues[SI91X_NETWORK_CMD].command_timeout = 0; } else { // Add the packet to event queue and set the async network event sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, packet); set_async_event(NCP_HOST_NETWORK_NOTIFICATION_EVENT); } // Check If the frame type is valid. if ((frame_type == cmd_queues[SI91X_NETWORK_CMD].frame_type) || (frame_type == RSI_WLAN_RSP_IPCONFV6 && cmd_queues[SI91X_NETWORK_CMD].frame_type == RSI_WLAN_REQ_IPCONFV6)) { cmd_queues[SI91X_NETWORK_CMD].command_in_flight = false; cmd_queues[SI91X_NETWORK_CMD].frame_type = 0; } // Check if the frame type indicates a failed join operation or a disconnect if (((RSI_WLAN_RSP_IPCONFV4 == frame_type) && (frame_status != SL_STATUS_OK)) || (RSI_WLAN_RSP_IPV4_CHANGE == frame_type)) { // Reset current performance profile and set it to high performance reset_coex_current_performance_profile(); current_performance_profile = HIGH_PERFORMANCE; // check for command in flight and create dummy packets for respective queues to be cleared sli_handle_dhcp_and_rejoin_failure(cmd_queues[SI91X_NETWORK_CMD].sdk_context, buffer, frame_status); sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, packet); set_async_event(NCP_HOST_NETWORK_NOTIFICATION_EVENT); } break; } #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK case RSI_WLAN_RSP_CONN_ESTABLISH: frame_type = RSI_WLAN_RSP_SOCKET_ACCEPT; // fall-through case RSI_WLAN_RSP_SOCKET_CONFIG: case RSI_WLAN_RSP_SOCKET_CREATE: case RSI_WLAN_RSP_SOCKET_CLOSE: case RSI_WLAN_RSP_SELECT_REQUEST: case RSI_WLAN_RSP_SOCKET_READ_DATA: // Socket read data response only is expected incase of failure case RSI_WLAN_RSP_SOCKET_ACCEPT: case RSI_WLAN_RSP_REMOTE_TERMINATE: { // Find relevant socket sl_si91x_packet_t *socket_packet = (sl_si91x_packet_t *)data; sli_si91x_socket_t *socket = get_socket_from_packet(socket_packet); sli_si91x_command_queue_t *socket_command_queue; if ((socket == NULL) || (frame_type == RSI_WLAN_RSP_SELECT_REQUEST) || (frame_type == RSI_WLAN_RSP_SOCKET_CREATE) || (frame_type == RSI_WLAN_RSP_SOCKET_CONFIG)) { socket_command_queue = &cmd_queues[SI91X_SOCKET_CMD]; } else { socket_command_queue = &socket->command_queue; } if (frame_type == RSI_WLAN_RSP_SELECT_REQUEST) { // Allocate a buffer for the response packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Set frame status, queue ID, and command type for the network response node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_SOCKET_CMD; node->host_packet = buffer; node->sdk_context = NULL; // and set asynchronous socket notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_SOCKET_CMD].event_queue, packet); set_async_event(NCP_HOST_SOCKET_NOTIFICATION_EVENT); break; } ++socket_command_queue->rx_counter; if ((socket_command_queue->command_timeout != 0) && (sl_si91x_host_elapsed_time(socket_command_queue->command_tickcount) > (socket_command_queue->command_timeout))) { sl_si91x_host_free_buffer(buffer); socket_command_queue->command_tickcount = 0; socket_command_queue->command_timeout = 0; break; } if (frame_type == RSI_WLAN_RSP_SOCKET_READ_DATA && socket_command_queue->frame_type == frame_type) { buffer->id = (uint8_t)(socket->command_queue.packet_id); socket_command_queue->command_in_flight = false; socket_command_queue->frame_type = 0; sli_si91x_add_to_queue(&socket->rx_data_queue, buffer); sli_si91x_set_socket_event(1 << socket->index); break; } // Allocate a buffer for the response packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Set frame status, queue ID, and command type for the socket response node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_SOCKET_CMD; node->host_packet = buffer; // Check if the frame type is valid if (socket_command_queue->frame_type == frame_type) { node->sdk_context = socket_command_queue->sdk_context; node->flags = socket_command_queue->flags; // node->packet_id = socket_command_queue->packet_id; buffer->id = socket_command_queue->packet_id; packet->id = socket_command_queue->packet_id; } else { node->sdk_context = NULL; node->flags = 0; // node->packet_id = 0; buffer->id = 0; packet->id = 0; } // Check if it's a response packet, and handle accordingly if ((socket_command_queue->flags & SI91X_PACKET_RESPONSE_STATUS) && (socket_command_queue->frame_type == frame_type)) { // Check if the response packet should be free or not if ((socket_command_queue->flags & SI91X_PACKET_RESPONSE_PACKET) == 0) { node->host_packet = NULL; sl_si91x_host_free_buffer(buffer); } // Add the response packet to the socket response queue and set the socket response event sli_si91x_add_to_queue(&socket_command_queue->rx_queue, packet); if (socket_command_queue == &cmd_queues[SI91X_SOCKET_CMD]) { sli_si91x_set_event(NCP_HOST_SOCKET_RESPONSE_EVENT); } else { sli_si91x_set_socket_event(1 << socket->index); } socket_command_queue->command_tickcount = 0; socket_command_queue->command_timeout = 0; } else { // and set asynchronous socket notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_SOCKET_CMD].event_queue, packet); set_async_event(NCP_HOST_SOCKET_NOTIFICATION_EVENT); } // If the frame_type matches the expected frame_type for the socket command // mark the command as not in flight and clear the frame_type if (frame_type == socket_command_queue->frame_type) { socket_command_queue->command_in_flight = false; socket_command_queue->frame_type = 0; } break; } #endif // Handle TCP ACK Indication response case RSI_WLAN_RSP_TCP_ACK_INDICATION: { // Allocate memory for a new packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Populate the packet's information node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_SOCKET_CMD; node->host_packet = buffer; node->sdk_context = NULL; node->flags = 0; // node->packet_id = 0; buffer->id = 0; packet->id = 0; // Add the packet to the socket event queue and set the asynchronous socket notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_SOCKET_CMD].event_queue, packet); set_async_event(NCP_HOST_SOCKET_NOTIFICATION_EVENT); break; } #ifdef SLI_SI91X_INTERNAL_HTTP_CLIENT case RSI_WLAN_RSP_HTTP_CLIENT_GET: case RSI_WLAN_RSP_HTTP_CLIENT_POST: case RSI_WLAN_RSP_HTTP_CLIENT_POST_DATA: { ++cmd_queues[SI91X_NETWORK_CMD].rx_counter; if (cmd_queues[SI91X_NETWORK_CMD].frame_type == RSI_WLAN_RSP_HTTP_CLIENT_GET) { // If it's an HTTP GET response, check if the frame_status is not OK or if end_of_data is set to 1. sl_si91x_packet_t *get_response_packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL); const uint16_t *end_of_data = (uint16_t *)&get_response_packet->data; if (frame_status != SL_STATUS_OK || *end_of_data == 1) { // Mark the command as not in flight and clear the frame_type cmd_queues[SI91X_NETWORK_CMD].command_in_flight = false; cmd_queues[SI91X_NETWORK_CMD].frame_type = 0; } } else { // For other HTTP responses, mark the command as not in flight and clear the frame_type cmd_queues[SI91X_NETWORK_CMD].command_in_flight = false; cmd_queues[SI91X_NETWORK_CMD].frame_type = 0; } // Allocate memory for a new packet status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Populate the packet's information node->host_packet = buffer; node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_NETWORK_CMD; node->sdk_context = cmd_queues[SI91X_NETWORK_CMD].sdk_context; node->flags = cmd_queues[SI91X_NETWORK_CMD].flags; // node->packet_id = cmd_queues[SI91X_NETWORK_CMD].packet_id; buffer->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; packet->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; // Add the packet to the network event queue and set the asynchronous network notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, packet); set_async_event(NCP_HOST_NETWORK_NOTIFICATION_EVENT); break; } case RSI_WLAN_RSP_HTTP_ABORT: case RSI_WLAN_RSP_HTTP_CLIENT_PUT: { ++cmd_queues[SI91X_NETWORK_CMD].rx_counter; status = sl_si91x_host_allocate_buffer(&packet, SL_WIFI_RX_FRAME_BUFFER, sizeof(sli_si91x_queue_packet_t), 1000); if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n"); BREAKPOINT(); } node = sl_si91x_host_get_buffer_data(packet, 0, &temp); // Populate the packet's information node->frame_status = frame_status; node->firmware_queue_id = RSI_WLAN_MGMT_Q; node->command_type = SI91X_NETWORK_CMD; node->sdk_context = cmd_queues[SI91X_NETWORK_CMD].sdk_context; node->flags = cmd_queues[SI91X_NETWORK_CMD].flags; // node->packet_id = command_trace[SI91X_NETWORK_CMD].packet_id; buffer->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; packet->id = cmd_queues[SI91X_NETWORK_CMD].packet_id; if (((cmd_queues[SI91X_NETWORK_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) == SI91X_PACKET_RESPONSE_STATUS) && (cmd_queues[SI91X_NETWORK_CMD].frame_type == frame_type)) { // If it's a response status and the frame_type matches, set host_packet to NULL and free the buffer node->host_packet = NULL; sl_si91x_host_free_buffer(buffer); if (sl_si91x_host_elapsed_time(cmd_queues[SI91X_NETWORK_CMD].command_tickcount) <= (cmd_queues[SI91X_NETWORK_CMD].command_timeout)) { // Add the packet to the network response queue and set the network response event sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].rx_queue, packet); sli_si91x_set_event(NCP_HOST_NETWORK_RESPONSE_EVENT); } else { // no user thread is waiting for the response so flush the packet and buffer sl_si91x_host_free_buffer(packet); if ((cmd_queues[SI91X_NETWORK_CMD].flags & SI91X_PACKET_RESPONSE_STATUS) != SI91X_PACKET_RESPONSE_STATUS) { sl_si91x_host_free_buffer(buffer); } } } else { // For other cases, set host_packet to buffer and add it to the network event queue node->host_packet = buffer; sli_si91x_add_to_queue(&cmd_queues[SI91X_NETWORK_CMD].event_queue, packet); set_async_event(NCP_HOST_NETWORK_NOTIFICATION_EVENT); } if (frame_type == cmd_queues[SI91X_NETWORK_CMD].frame_type) { // mark the command as not in flight and clear the frame_type cmd_queues[SI91X_NETWORK_CMD].command_in_flight = false; cmd_queues[SI91X_NETWORK_CMD].frame_type = 0; cmd_queues[SI91X_NETWORK_CMD].command_tickcount = 0; cmd_queues[SI91X_NETWORK_CMD].command_timeout = 0; } break; } #endif default: { // frame_type doesn't match any known cases if (PRINT_ERROR_LOGS) { PRINT_ERROR_STATUS(INFO_TAG, frame_type); } // Free the buffer sl_si91x_host_free_buffer(buffer); break; } } break; } case RSI_WLAN_DATA_Q: { // Erase queue ID as it overlays with the length field which is only 24-bit data[1] &= 0xF; if (frame_type == RSI_RECEIVE_RAW_DATA) { // If the frame type is raw data reception #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK SL_DEBUG_LOG("Raw Data\n"); sl_si91x_packet_t *socket_packet = (sl_si91x_packet_t *)data; sli_si91x_socket_t *socket = NULL; int socket_id = sli_si91x_get_socket_id(socket_packet); socket = sli_si91x_get_socket_from_id(socket_id, LISTEN, -1); // Check if we found a matching socket if (socket != NULL) { buffer->id = (uint8_t)(socket->command_queue.packet_id); // Check if command has timed out if (socket->command_queue.command_tickcount == 0 || (sl_si91x_host_elapsed_time(socket->command_queue.command_tickcount) <= (socket->command_queue.command_timeout))) { if (((socket->command_queue.frame_type == RSI_WLAN_RSP_SOCKET_READ_DATA) || (socket->command_queue.frame_type == socket_packet->command)) && socket->command_queue.command_in_flight && socket->command_queue.flags & SI91X_PACKET_RESPONSE_PACKET) { socket->command_queue.command_in_flight = false; sli_si91x_add_to_queue(&socket->rx_data_queue, buffer); sli_si91x_set_socket_event(1 << socket->index); } else { sli_si91x_add_to_queue(&socket->rx_data_queue, buffer); set_async_event(NCP_HOST_SOCKET_DATA_NOTIFICATION_EVENT); } } else { sli_si91x_add_to_queue(&socket->rx_data_queue, buffer); set_async_event(NCP_HOST_SOCKET_DATA_NOTIFICATION_EVENT); // sl_si91x_host_free_buffer(buffer); } socket->command_queue.command_tickcount = 0; socket->command_queue.command_timeout = 0; } #else // If SLI_SI91X_OFFLOAD_NETWORK_STACK is not defined, process the data frame and free the buffer. sl_si91x_host_process_data_frame(SL_WIFI_CLIENT_INTERFACE, buffer); sl_si91x_host_free_buffer(buffer); #endif } else if (frame_type == SL_SI91X_WIFI_RX_DOT11_DATA) { ++cmd_queues[SI91X_WLAN_CMD].rx_counter; // Marking a received frame as not in flight when it matches the expected type if (frame_type == cmd_queues[SI91X_WLAN_CMD].frame_type) { cmd_queues[SI91X_WLAN_CMD].command_in_flight = false; cmd_queues[SI91X_WLAN_CMD].command_tickcount = 0; cmd_queues[SI91X_WLAN_CMD].command_timeout = 0; } // Add it to the WLAN event queue and set the WLAN notification event sli_si91x_add_to_queue(&cmd_queues[SI91X_WLAN_CMD].event_queue, buffer); set_async_event(NCP_HOST_WLAN_NOTIFICATION_EVENT); } break; } #ifdef SLI_SI91X_ENABLE_BLE case RSI_BT_Q: { SL_DEBUG_LOG("Received BLE packet\n"); // Increment the receive counter for the Bluetooth command ++cmd_queues[SI91X_BT_CMD].rx_counter; if (frame_type == cmd_queues[SI91X_BT_CMD].frame_type) { // Mark the command as not in flight and clear the frame_type cmd_queues[SI91X_BT_CMD].command_in_flight = false; cmd_queues[SI91X_BT_CMD].frame_type = 0; } // Process the Bluetooth response data and free the buffer rsi_driver_process_bt_resp_handler(data); sl_si91x_host_free_buffer(buffer); break; } #endif default: { // If the frame_type doesn't match any known cases // Free the buffer sl_si91x_host_free_buffer(buffer); break; } } sli_submit_rx_buffer(); } else { event &= ~SL_SI91X_NCP_HOST_BUS_RX_EVENT; // Reset the event flag } if (event & SL_SI91X_ALL_TX_PENDING_COMMAND_EVENTS) { // This condition is checked before writing frames to the bus for (int i = 0; i < SI91X_CMD_MAX; i++) { if (!(event & (SL_SI91X_TX_PENDING_FLAG(i)))) { continue; } if (cmd_queues[i].command_in_flight == true) { tx_command_queues_command_in_flight_status |= SL_SI91X_TX_PENDING_FLAG(i); continue; } else { tx_command_queues_command_in_flight_status &= ~SL_SI91X_TX_PENDING_FLAG(i); } // Check if the bus is ready for a packet if (!sli_si91x_is_bus_ready(global_queue_block)) { break; } bus_write_frame(&cmd_queues[i], i, SL_WIFI_CONTROL_BUFFER, &global_queue_block); if (sli_si91x_buffer_queue_empty(&cmd_queues[i].tx_queue)) { event &= ~SL_SI91X_TX_PENDING_FLAG(i); tx_command_queues_status &= ~SL_SI91X_TX_PENDING_FLAG(i); } } } #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK if (tx_socket_command_queues_status & (~(tx_command_queues_command_in_flight_status))) { for (int i = 0; i < NUMBER_OF_SOCKETS; i++) { if (sli_si91x_sockets[i] != NULL && !sli_si91x_buffer_queue_empty(&sli_si91x_sockets[i]->command_queue.tx_queue)) { if (sli_si91x_sockets[i]->command_queue.command_in_flight == true) { tx_socket_command_command_in_flight_queues_status |= (1 << i); continue; } else { tx_socket_command_command_in_flight_queues_status &= ~(1 << i); } // Check if the bus is ready for a packet if (!sli_si91x_is_bus_ready(global_queue_block)) { break; } // Send the socket specific command bus_write_frame(&sli_si91x_sockets[i]->command_queue, SI91X_SOCKET_CMD, SL_WIFI_CONTROL_BUFFER, &global_queue_block); if (sli_si91x_buffer_queue_empty(&sli_si91x_sockets[i]->command_queue.tx_queue)) { tx_socket_command_queues_status &= ~(1 << i); } } } // Clear the event flag for socket queues if there are no commands left if (tx_socket_command_queues_status == 0) { event &= ~SL_SI91X_SOCKET_COMMAND_TX_PENDING_EVENT; } } if (event & SL_SI91X_SOCKET_DATA_TX_PENDING_EVENT) { bool all_socket_data_sent = true; // Check each socket if it has something to send for (int i = 0; i < NUMBER_OF_SOCKETS; ++i) { if (sli_si91x_sockets[i] != NULL && !sli_si91x_buffer_queue_empty(&sli_si91x_sockets[i]->tx_data_queue)) { all_socket_data_sent = false; // Check if the bus is ready for a packet if (!sli_si91x_is_bus_ready(global_queue_block)) { break; } sl_status_t status = bus_write_data_frame(&sli_si91x_sockets[i]->tx_data_queue); if (status == SL_STATUS_OK) { --sli_si91x_sockets[i]->data_buffer_count; } if (sli_si91x_buffer_queue_empty(&sli_si91x_sockets[i]->tx_data_queue)) { tx_socket_data_queues_status &= ~(1 << i); } } } // Clear event bit if we confirmed no more packets to send if (all_socket_data_sent) { event &= ~SL_SI91X_SOCKET_DATA_TX_PENDING_EVENT; } } #endif if (event & SL_SI91X_GENERIC_DATA_TX_PENDING_EVENT) { // Check if the bus is ready for a packet sl_si91x_bus_read_interrupt_status(&interrupt_status); if (!(interrupt_status & RSI_BUFFER_FULL)) { bus_write_data_frame(&sli_tx_data_queue); if (sli_si91x_buffer_queue_empty(&sli_tx_data_queue)) { event &= ~SL_SI91X_GENERIC_DATA_TX_PENDING_EVENT; tx_generic_socket_data_queues_status &= ~(SL_SI91X_GENERIC_DATA_TX_PENDING_EVENT); } } #ifdef SLI_SI91X_MCU_INTERFACE else { unmask_ta_interrupt(TA_RSI_BUFFER_FULL_CLEAR_EVENT); } #endif } if (event & SL_SI91X_TERMINATE_BUS_THREAD_EVENT) { // Clear the termination event flag event &= ~SL_SI91X_TERMINATE_BUS_THREAD_EVENT; // Acknowledge the termination request osEventFlagsSet(si91x_events, SL_SI91X_TERMINATE_BUS_THREAD_EVENT_ACK); // Terminate the current thread osThreadTerminate(osThreadGetId()); } } //To suppress warning unused parameter, no code effect UNUSED_PARAMETER(event); } static sl_status_t bus_write_frame(sli_si91x_command_queue_t *queue, sl_si91x_command_type_t command_type, sl_wifi_buffer_type_t buffer_type, bool *global_queue_block) { UNUSED_PARAMETER(buffer_type); UNUSED_PARAMETER(command_type); sl_status_t status; sl_wifi_buffer_t *buffer; sl_si91x_packet_t *packet; sli_si91x_queue_packet_t *node = NULL; if ((current_performance_profile != HIGH_PERFORMANCE) && (si91x_req_wakeup() != SL_STATUS_OK)) { return SL_STATUS_TIMEOUT; } status = sli_si91x_remove_from_queue(&queue->tx_queue, &buffer); if (status != SL_STATUS_OK) { if (current_performance_profile != HIGH_PERFORMANCE) { sl_si91x_host_clear_sleep_indicator(); } VERIFY_STATUS_AND_RETURN(status); } node = sl_si91x_host_get_buffer_data(buffer, 0, NULL); packet = sl_si91x_host_get_buffer_data(node->host_packet, 0, NULL); uint16_t length = packet->length; // Modify the packet's descriptor to include the firmware queue ID in the length field packet->desc[1] |= (node->firmware_queue_id << 4); if (packet->command) { // Set the global_queue_block flag if it is present in the packet's flags if (SI91X_PACKET_GLOBAL_QUEUE_BLOCK & node->flags) { *global_queue_block = true; } if (SI91X_PACKET_WITH_ASYNC_RESPONSE != (node->flags & SI91X_PACKET_WITH_ASYNC_RESPONSE)) { // Update trace information with packet details // If the packet doesn't have an async response, mark the command as in flight queue->command_in_flight = true; queue->packet_id = node->host_packet->id; queue->firmware_queue_id = node->firmware_queue_id; queue->frame_type = packet->command; queue->flags = node->flags; queue->command_timeout = node->command_timeout; queue->command_tickcount = node->command_tickcount; queue->sdk_context = node->sdk_context; } } #ifdef SLI_SI91X_MCU_INTERFACE if ((packet->command == RSI_COMMON_RSP_TA_M4_COMMANDS) || (packet->command == RSI_WLAN_REQ_SET_CERTIFICATE)) { // set flag sli_si91x_update_flash_command_status(true); } #endif // Write the frame to the bus using packet data and length status = sl_si91x_bus_write_frame(packet, packet->data, length); #ifdef SLI_SI91X_MCU_INTERFACE if (packet->desc[2] == RSI_COMMON_REQ_SOFT_RESET) { sli_si91x_config_m4_dma_desc_on_reset(); } #endif // Handle errors during frame writing if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n BUS_WRITE_ERROR \r\n"); BREAKPOINT(); } SL_DEBUG_LOG("<>>>> Tx -> queueId : %u, frameId : 0x%x, length : %u\n", node->firmware_queue_id, packet->command, length); if (current_performance_profile != HIGH_PERFORMANCE) { sl_si91x_host_clear_sleep_indicator(); } #ifdef SLI_SI91X_ENABLE_BLE if (command_type == SI91X_BT_CMD) { rsi_bt_common_tx_done(packet); } #endif sl_si91x_host_free_buffer(node->host_packet); sl_si91x_host_free_buffer(buffer); queue->tx_counter++; return SL_STATUS_OK; } // This function is called for writing data static sl_status_t bus_write_data_frame(sl_si91x_buffer_queue_t *queue) { sl_status_t status; sl_wifi_buffer_t *buffer; sl_si91x_packet_t *packet; if ((current_performance_profile != HIGH_PERFORMANCE) && (si91x_req_wakeup() != SL_STATUS_OK)) { return SL_STATUS_TIMEOUT; } status = sli_si91x_remove_from_queue(queue, &buffer); if (status != SL_STATUS_OK) { if (current_performance_profile != HIGH_PERFORMANCE) { sl_si91x_host_clear_sleep_indicator(); } VERIFY_STATUS_AND_RETURN(status); } packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL); uint16_t length = packet->length; // Modify the packet's descriptor to include the firmware queue ID in the length field packet->desc[1] |= (5 << 4); // Write the frame to the bus using packet data and length status = sl_si91x_bus_write_frame(packet, packet->data, length); // Handle errors during frame writing if (status != SL_STATUS_OK) { SL_DEBUG_LOG("\r\n BUS_WRITE_ERROR \r\n"); BREAKPOINT(); } SL_DEBUG_LOG("<>>>> Tx -> queueId : %u, frameId : 0x%x, length : %u\n", 5, 0, length); if (current_performance_profile != HIGH_PERFORMANCE) { sl_si91x_host_clear_sleep_indicator(); } sl_si91x_host_free_buffer(buffer); return SL_STATUS_OK; } static void set_async_event(uint32_t event_mask) { osEventFlagsSet(si91x_async_events, event_mask); } // Function to check if the bus is ready for writing bool sli_si91x_is_bus_ready(bool global_queue_block) { if (global_queue_block) { return false; } uint16_t interrupt_status = 0; sl_si91x_bus_read_interrupt_status(&interrupt_status); if (interrupt_status & RSI_BUFFER_FULL) { #ifdef SLI_SI91X_MCU_INTERFACE unmask_ta_interrupt(TA_RSI_BUFFER_FULL_CLEAR_EVENT); #endif return false; } return true; } #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK static sli_si91x_socket_t *get_socket_from_packet(sl_si91x_packet_t *socket_packet) { int socket_id = sli_si91x_get_socket_id(socket_packet); if (socket_packet->command == RSI_WLAN_RSP_CONN_ESTABLISH) { socket_packet->command = RSI_WLAN_RSP_SOCKET_ACCEPT; } if (socket_packet->command == RSI_WLAN_RSP_SOCKET_CREATE) { sl_si91x_socket_create_response_t *socket_create_response = ((sl_si91x_socket_create_response_t *)socket_packet->data); return sli_si91x_get_socket_from_id( -1, RESET, (int16_t)(socket_create_response->socket_type[0] | (socket_create_response->socket_type[1] << 8))); } else if (socket_packet->command == RSI_WLAN_RSP_SOCKET_ACCEPT) { const sli_si91x_socket_t *si91x_socket = sli_si91x_get_socket_from_id(socket_id, RESET, -1); return get_si91x_socket(si91x_socket->client_id); } else if (socket_packet->command == RSI_WLAN_RSP_SOCKET_CLOSE) { return sli_si91x_get_socket_from_id(socket_id, RESET, -1); } else { return sli_si91x_get_socket_from_id(socket_id, LISTEN, -1); } } #endif