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