1 /***************************************************************************/ /**
2  * @file
3  * @brief
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 #include "sl_constants.h"
31 #include "sl_si91x_types.h"
32 #include "sl_si91x_driver.h"
33 #include "sl_net_si91x.h"
34 #include "sl_net_constants.h"
35 #include "sl_net_rsi_utility.h"
36 #include "sl_net_si91x_integration_handler.h"
37 #if defined(SL_WIFI_COMPONENT_INCLUDED)
38 #include "sl_wifi.h"
39 #endif
40 #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK
41 #include "sl_si91x_socket_constants.h"
42 #include "sl_si91x_socket_utility.h"
43 #include "sl_ip_types.h"
44 #endif
45 
46 extern sli_si91x_command_queue_t cmd_queues[SI91X_CMD_MAX];
47 
48 #ifdef SLI_SI91X_SOCKETS
49 #include "sl_si91x_socket_utility.h"
50 #include "sl_si91x_socket_callback_framework.h"
51 #endif
52 #include "sl_si91x_core_utilities.h"
53 
54 #ifdef SLI_SI91X_EMBEDDED_MQTT_CLIENT
55 #include "si91x_mqtt_client_callback_framework.h"
56 #include "si91x_mqtt_client_utility.h"
57 #endif
58 
59 #ifdef SLI_SI91X_INTERNAL_SNTP_CLIENT
60 #include "si91x_sntp_client_callback_framework.h"
61 #endif
62 
63 #ifdef SLI_SI91X_INTERNAL_HTTP_CLIENT
64 #include "sl_si91x_http_client_callback_framework.h"
65 #endif
66 
67 #ifdef SLI_SI91X_EMBEDDED_MQTT_CLIENT
68 /**
69  * A internal function to handle to asynchronous mqtt client events.
70  */
handle_mqtt_client_asynch_events(sli_si91x_queue_packet_t * mqtt_asyn_packet)71 static void handle_mqtt_client_asynch_events(sli_si91x_queue_packet_t *mqtt_asyn_packet)
72 {
73   sl_si91x_packet_t *raw_rx_packet = sl_si91x_host_get_buffer_data(mqtt_asyn_packet->host_packet, 0, NULL);
74   sl_mqtt_client_t *mqtt_client;
75 
76   raw_rx_packet->desc[12] = mqtt_asyn_packet->frame_status & 0xFF;        // Lower 8 bits
77   raw_rx_packet->desc[13] = (mqtt_asyn_packet->frame_status >> 8) & 0xFF; // Upper 8 bits
78   //Variable to indicate whether a disconnect event is related to a keep-alive terminate error.
79   bool is_keep_alive_response_related_disconnect =
80     (raw_rx_packet->command == RSI_WLAN_RSP_EMB_MQTT_CLIENT
81      && mqtt_asyn_packet->frame_status == (SL_STATUS_SI91X_MQTT_KEEP_ALIVE_TERMINATE_ERROR & ~BIT(16)));
82 
83   // Since these responses are unsolicited, We need to create a context for them.
84   if (raw_rx_packet->command == RSI_WLAN_RSP_MQTT_REMOTE_TERMINATE
85       || raw_rx_packet->command == RSI_WLAN_RSP_EMB_MQTT_PUBLISH_PKT || raw_rx_packet->command == RSI_WLAN_RSP_JOIN
86       || is_keep_alive_response_related_disconnect) {
87 
88     sli_si91x_get_mqtt_client(&mqtt_client);
89 
90     if (mqtt_client == NULL) {
91       // Drop MQTT client event, if the client is either connecting or disconnected
92       SL_DEBUG_LOG("Dropping mqtt client event, Si91x Event: %hu", raw_rx_packet->command);
93       return;
94     }
95 
96     if (mqtt_client->state == SL_MQTT_CLIENT_DISCONNECTED) {
97       // Drop MQTT client event disconnect, if the client is already in disconnected
98       // This can happen if MQTT client is already disconnected state and NWP sends a rejoin failure event.
99       SL_DEBUG_LOG("Dropping mqtt disconnect event: %hu", raw_rx_packet->command);
100       return;
101     }
102 
103     // Send CONNECT_FAILED_EVENT if JOIN is received during TA_INIT state
104     if ((raw_rx_packet->command == RSI_WLAN_RSP_JOIN || raw_rx_packet->command == RSI_WLAN_RSP_DISCONNECT)
105         && mqtt_client->state == SL_MQTT_CLIENT_TA_INIT) {
106       // Build MQTT SDK context for asynchronous MQTT events
107       sli_si91x_build_mqtt_sdk_context_if_async(SL_MQTT_CLIENT_CONNECTED_EVENT,
108                                                 mqtt_client,
109                                                 NULL,
110                                                 NULL,
111                                                 0,
112                                                 (sl_si91x_mqtt_client_context_t **)&mqtt_asyn_packet->sdk_context);
113     } else {
114       // Build MQTT SDK context for asynchronous MQTT events
115       sli_si91x_build_mqtt_sdk_context_if_async(
116         (raw_rx_packet->command == RSI_WLAN_RSP_MQTT_REMOTE_TERMINATE || raw_rx_packet->command == RSI_WLAN_RSP_JOIN
117          || is_keep_alive_response_related_disconnect)
118           ? SL_MQTT_CLIENT_DISCONNECTED_EVENT
119           : SL_MQTT_CLIENT_MESSAGED_RECEIVED_EVENT,
120         mqtt_client,
121         NULL,
122         NULL,
123         0,
124         (sl_si91x_mqtt_client_context_t **)&mqtt_asyn_packet->sdk_context);
125     }
126   }
127 
128   sl_si91x_mqtt_client_context_t *sdk_context = (sl_si91x_mqtt_client_context_t *)mqtt_asyn_packet->sdk_context;
129 
130   if (sdk_context == NULL) {
131     return;
132   }
133 
134   SL_DEBUG_LOG("handle_mqtt_client_asynch_events: event %x", sdk_context->event);
135 
136   uint16_t si91x_event_status = get_si91x_frame_status(raw_rx_packet);
137   sl_status_t event_status    = convert_and_save_firmware_status(si91x_event_status);
138 
139   // Handle MQTT events
140   sli_si91x_mqtt_event_handler(event_status, sdk_context, raw_rx_packet);
141 }
142 #endif
143 
144 /*static void si91x_node_free_function(sl_wifi_buffer_t *buffer)
145 {
146   sl_si91x_host_free_buffer(buffer);
147 }*/
148 
sl_net_si91x_event_dispatch_handler(sli_si91x_queue_packet_t * data,sl_si91x_packet_t * packet)149 void sl_net_si91x_event_dispatch_handler(sli_si91x_queue_packet_t *data, sl_si91x_packet_t *packet)
150 {
151   sl_status_t status;
152   sl_net_event_t service_event;
153 #ifdef SLI_SI91X_INTERNAL_HTTP_CLIENT
154   sl_http_client_event_t http_event;
155 #endif
156 
157 #ifdef SLI_SI91X_EMBEDDED_MQTT_CLIENT
158   // Handle MQTT client-specific events
159   if (packet->command == RSI_WLAN_REQ_EMB_MQTT_CLIENT || packet->command == RSI_WLAN_RSP_EMB_MQTT_PUBLISH_PKT
160       || packet->command == RSI_WLAN_RSP_MQTT_REMOTE_TERMINATE) {
161     handle_mqtt_client_asynch_events(data);
162     return;
163   } else if (packet->command == RSI_WLAN_RSP_JOIN) {
164     handle_mqtt_client_asynch_events(data);
165   }
166 #endif
167 
168 #ifdef SLI_SI91X_INTERNAL_SNTP_CLIENT
169   // Handle SNTP client events
170   if (packet->command == RSI_WLAN_RSP_SNTP_CLIENT) {
171     sli_si91x_sntp_event_handler(data);
172     return;
173   }
174 #endif
175 
176 #ifdef SLI_SI91X_SOCKETS
177   // Handle SI91X socket-related events
178   bool is_socket_command =
179     (packet->command == RSI_WLAN_REQ_SOCKET_ACCEPT || packet->command == RSI_WLAN_RSP_REMOTE_TERMINATE
180      || packet->command == RSI_RECEIVE_RAW_DATA || packet->command == RSI_WLAN_RSP_TCP_ACK_INDICATION
181      || packet->command == RSI_WLAN_RSP_SELECT_REQUEST);
182   if (is_socket_command) {
183     sl_si91x_packet_t *raw_rx_packet = packet;
184     uint16_t si91x_event_status      = get_si91x_frame_status(raw_rx_packet);
185 
186     sl_status_t event_status = convert_and_save_firmware_status(si91x_event_status);
187     si91x_socket_event_handler(event_status, (sl_si91x_socket_context_t *)data->sdk_context, raw_rx_packet);
188   }
189 #endif
190 
191 #if defined(SL_WIFI_COMPONENT_INCLUDED)
192   // Retrieve the current operation mode (e.g., client, AP, concurrent).
193   sl_si91x_operation_mode_t current_operation_mode = get_opermode();
194 
195   // Determine if a Wi-Fi client is disconnected from the access point.
196   // This includes cases where the device is operating as an access point (AP mode)
197   // or in concurrent mode where the AP VAP ID is relevant.
198   bool is_client_disconnected_from_ap =
199     (packet->command == RSI_WLAN_RSP_CLIENT_DISCONNECTED
200      || (packet->command == RSI_WLAN_RSP_DISCONNECT
201          && (current_operation_mode == SL_SI91X_ACCESS_POINT_MODE
202              || (current_operation_mode == SL_SI91X_CONCURRENT_MODE && packet->desc[7] == SL_SI91X_WIFI_AP_VAP_ID))));
203 
204   // Determine if a TX flush is required.
205   // This is true for scenarios such as join failures, IP address changes, and disconnections.
206   bool is_tx_flush_required = (((packet->command == RSI_WLAN_RSP_JOIN) && (data->frame_status != SL_STATUS_OK))
207                                || packet->command == RSI_WLAN_RSP_IPV4_CHANGE
208                                || packet->command == RSI_WLAN_RSP_IPCONFV4 || packet->command == RSI_WLAN_RSP_IPCONFV6
209                                || packet->command == RSI_WLAN_RSP_DISCONNECT
210                                || packet->command == RSI_WLAN_RSP_AP_STOP);
211 
212   // Handle the scenario where a Wi-Fi client disconnects from the AP.
213   if (is_client_disconnected_from_ap) {
214     sl_mac_address_t mac_address = { 0 };
215 
216     // Extract the MAC address based on the specific disconnection command.
217     if (packet->command == RSI_WLAN_RSP_CLIENT_DISCONNECTED) {
218       // For a client disconnection, the MAC address is in the packet data.
219       memcpy((uint8_t *)&mac_address, (uint8_t *)packet->data, sizeof(sl_mac_address_t));
220     } else {
221       // For a general disconnect, the MAC address is in the SDK context.
222       memcpy((uint8_t *)&mac_address, (uint8_t *)data->sdk_context, sizeof(sl_mac_address_t));
223     }
224 
225 #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK
226     // Retrieve the destination IP address associated with the MAC address.
227     const sl_ip_address_t *destination_ip_address = sli_si91x_get_ap_client_ip_address_from_mac_address(mac_address);
228 
229     // If an IP address is found, flush all socket TX queues for that destination.
230     if (destination_ip_address != NULL) {
231       sli_si91x_flush_all_socket_tx_queues_based_on_dest_ip_address(data->frame_status, destination_ip_address);
232     }
233 #endif
234 
235     // Update AP client information after handling the disconnection.
236     sli_si91x_update_ap_client_info();
237 
238   } else if (is_tx_flush_required) {
239     // Handle cases where a general TX flush might be needed due to connection changes.
240 
241     // Check if the condition necessitates a general TX Wi-Fi queue flush.
242     bool is_general_tx_queue_flush_needed =
243       (packet->command == RSI_WLAN_RSP_JOIN || packet->command == RSI_WLAN_RSP_IPV4_CHANGE
244        || packet->command == RSI_WLAN_RSP_IPCONFV4 || packet->command == RSI_WLAN_RSP_IPCONFV6
245        || (packet->command == RSI_WLAN_RSP_DISCONNECT
246            && (current_operation_mode == SL_SI91X_CLIENT_MODE
247                || (current_operation_mode == SL_SI91X_CONCURRENT_MODE
248                    && packet->desc[7] == SL_SI91X_WIFI_CLIENT_VAP_ID))));
249 
250     // If a general flush is required, clear all TX Wi-Fi queues as the connection is lost.
251     if (is_general_tx_queue_flush_needed) {
252       sli_si91x_flush_all_tx_wifi_queues(SL_STATUS_WIFI_CONNECTION_LOST);
253 #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK
254       // Flush the select request table based on the provided frame_status
255       sli_si91x_flush_select_request_table(data->frame_status);
256 #endif
257     }
258 
259 #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK
260     // Define the VAP ID for the client (default to client VAP ID).
261     uint8_t vap_id_for_flush = SL_SI91X_WIFI_CLIENT_VAP_ID;
262 
263     // In concurrent mode with an AP stop command, use the AP VAP ID for the flush.
264     if (current_operation_mode == SL_SI91X_CONCURRENT_MODE && packet->command == RSI_WLAN_RSP_AP_STOP) {
265       vap_id_for_flush = SL_SI91X_WIFI_AP_VAP_ID;
266     }
267 
268     // Flush all pending socket commands for the determined VAP ID.
269     sli_si91x_flush_all_socket_command_queues(data->frame_status, vap_id_for_flush);
270 
271     // Flush all pending socket data for the determined VAP ID.
272     sli_si91x_flush_all_socket_data_queues(vap_id_for_flush);
273 
274     // Shutdown and update the state of the sockets associated with the VAP ID.
275     sli_si91x_vap_shutdown(vap_id_for_flush);
276 #endif
277   }
278 #endif
279 
280   status = convert_si91x_event_to_sl_net_event(&packet->command, &service_event);
281   if (status == SL_STATUS_OK) {
282     SL_DEBUG_LOG("><<<< Got net event : %u\n", service_event);
283     sl_si91x_default_handler(service_event, data->host_packet);
284   }
285 #ifdef SLI_SI91X_INTERNAL_HTTP_CLIENT
286   // Check for sl_http_client_event_t
287   else if (convert_si91x_event_to_sl_http_client_event(&packet->command, &http_event) == SL_STATUS_OK) {
288     SL_DEBUG_LOG("\r\n>>> HTTP Event received: %u <<<\r\n", http_event);
289     sl_http_client_default_event_handler(http_event, data->host_packet, data->sdk_context);
290   }
291 #endif
292 }
293 
sli_si91x_network_cleanup_handler()294 void sli_si91x_network_cleanup_handler()
295 {
296 #ifdef SLI_SI91X_EMBEDDED_MQTT_CLIENT
297   sli_mqtt_client_cleanup();
298 #endif
299 }
300 
301 #ifdef SLI_SI91X_OFFLOAD_NETWORK_STACK
sli_si91x_flush_all_socket_tx_queues_based_on_dest_ip_address(uint16_t frame_status,const sl_ip_address_t * dest_ip_add)302 sl_status_t sli_si91x_flush_all_socket_tx_queues_based_on_dest_ip_address(uint16_t frame_status,
303                                                                           const sl_ip_address_t *dest_ip_add)
304 {
305   sl_status_t status;
306 
307   // Loop through all sockets
308   for (uint8_t index = 0; index < NUMBER_OF_SOCKETS; index++) {
309     // Check if the socket exists and matches the required VAP ID
310     if (sli_si91x_sockets[index] != NULL) {
311       bool is_same = 0;
312       if (dest_ip_add->type == SL_IPV4) {
313         const struct sockaddr_in *socket_address = (struct sockaddr_in *)&sli_si91x_sockets[index]->remote_address;
314         is_same = memcmp(dest_ip_add->ip.v4.bytes, &socket_address->sin_addr.s_addr, SL_IPV4_ADDRESS_LENGTH);
315       } else {
316         const struct sockaddr_in6 *ipv6_socket_address = &sli_si91x_sockets[index]->remote_address;
317         is_same                                        = memcmp(dest_ip_add->ip.v6.bytes,
318                          &ipv6_socket_address->sin6_addr.s6_addr,
319                          SL_IPV6_ADDRESS_LENGTH);
320       }
321       if (!is_same) {
322         // Flush the command queues for the current socket based on queue type
323         status = sli_si91x_flush_socket_command_queues_based_on_queue_type(index, frame_status);
324         // If flushing fails, return the error status immediately
325         VERIFY_STATUS_AND_RETURN(status);
326 
327         status = sli_si91x_flush_socket_data_queues_based_on_queue_type(index);
328         // If flushing fails, return the error status immediately
329         VERIFY_STATUS_AND_RETURN(status);
330 
331         // update the socket state to disconnected.
332         sli_si91x_sockets[index]->state = DISCONNECTED;
333       }
334     }
335   }
336   // Return SL_STATUS_OK if all sockets were processed successfully
337   return SL_STATUS_OK;
338 }
339 #endif
340