1 /***************************************************************************/ /**
2  * @file  sl_si91x_socket_utility.c
3  *******************************************************************************
4  * # License
5  * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
6  *******************************************************************************
7  *
8  * SPDX-License-Identifier: Zlib
9  *
10  * The licensor of this software is Silicon Laboratories Inc.
11  *
12  * This software is provided 'as-is', without any express or implied
13  * warranty. In no event will the authors be held liable for any damages
14  * arising from the use of this software.
15  *
16  * Permission is granted to anyone to use this software for any purpose,
17  * including commercial applications, and to alter it and redistribute it
18  * freely, subject to the following restrictions:
19  *
20  * 1. The origin of this software must not be misrepresented; you must not
21  *    claim that you wrote the original software. If you use this software
22  *    in a product, an acknowledgment in the product documentation would be
23  *    appreciated but is not required.
24  * 2. Altered source versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.
26  * 3. This notice may not be removed or altered from any source distribution.
27  *
28  ******************************************************************************/
29 
30 #include "sl_si91x_socket_utility.h"
31 #include "sl_si91x_socket_types.h"
32 #include "sl_si91x_socket_callback_framework.h"
33 #include "sl_status.h"
34 #include "sl_constants.h"
35 #include "sl_si91x_driver.h"
36 #include "sl_si91x_protocol_types.h"
37 #include "sl_si91x_socket_constants.h"
38 #include "sl_si91x_host_interface.h"
39 #include "sl_si91x_core_utilities.h"
40 #include "sl_rsi_utility.h"
41 #include "em_core.h"
42 #include <string.h>
43 #include <stdbool.h>
44 
45 /******************************************************
46  *               Macro Definitions
47  ******************************************************/
48 #define SLI_SI91X_SOCKET_ACCEPT_SUCCESS_EVENT (1 << 0)
49 #define SLI_SI91X_SOCKET_ACCEPT_FAILURE_EVENT (1 << 1)
50 
51 #ifndef SL_SOCKET_DEFAULT_BUFFER_LIMIT
52 #define SL_SOCKET_DEFAULT_BUFFER_LIMIT 3
53 #endif
54 
55 /******************************************************
56  *                    Structures
57  ******************************************************/
58 
59 typedef struct {
60   uint8_t in_use;
61   uint8_t select_id;
62   uint16_t frame_status;
63   union {
64     sl_si91x_socket_select_callback_t select_callback;
65     sl_si91x_socket_select_rsp_t *response_data;
66   };
67 } sli_si91x_select_request_t;
68 
69 /******************************************************
70  *               Static Function Declarations
71  ******************************************************/
72 
73 static void sli_si91x_clear_select_id(uint8_t flag);
74 static sli_si91x_select_request_t *sli_si91x_get_available_select_id(void);
75 
76 /**
77  * A internal function to check whether a particular port is available or not.
78  * @param port_number port_number which needs to be verified for availability.
79  * @return True if available else false.
80  */
81 static bool is_port_available(uint16_t port_number);
82 
83 /******************************************************
84  *               Variable Definitions
85  ******************************************************/
86 sli_si91x_socket_t *sli_si91x_sockets[NUMBER_OF_SOCKETS]                                     = { 0 };
87 static sl_si91x_socket_remote_termination_callback_t user_remote_socket_termination_callback = NULL;
88 static osMutexId_t sli_si91x_socket_mutex                                                    = NULL;
89 static uint8_t sli_si91x_max_select_count                                                    = 0;
90 
91 static sli_si91x_select_request_t *select_request_table = NULL;
92 //sl_si91x_buffer_queue_t sli_si91x_select_request_queue;
93 //sli_si91x_select_request_t *select_request_head = NULL;
94 sl_si91x_buffer_queue_t sli_si91x_select_response_queue;
95 
96 extern sli_si91x_command_queue_t cmd_queues[SI91X_CMD_MAX];
97 
98 osEventFlagsId_t si91x_socket_events        = 0;
99 osEventFlagsId_t si91x_socket_select_events = 0;
100 
101 extern volatile uint32_t tx_socket_command_queues_status;
102 
103 extern volatile uint32_t tx_socket_data_queues_status;
104 
105 /******************************************************
106  *               Function Definitions
107  ******************************************************/
108 
handle_accept_response(sli_si91x_socket_t * si91x_client_socket,const sl_si91x_rsp_ltcp_est_t * accept_response)109 void handle_accept_response(sli_si91x_socket_t *si91x_client_socket, const sl_si91x_rsp_ltcp_est_t *accept_response)
110 {
111   //Verifying socket existence
112   if (si91x_client_socket == NULL)
113     return;
114   // Update socket parameters based on the accept response
115   si91x_client_socket->id                         = accept_response->socket_id;
116   si91x_client_socket->local_address.sin6_port    = accept_response->src_port_num;
117   si91x_client_socket->remote_address.sin6_port   = accept_response->dest_port;
118   si91x_client_socket->mss                        = accept_response->mss;
119   si91x_client_socket->state                      = CONNECTED;
120   si91x_client_socket->remote_address.sin6_family = accept_response->ip_version == SL_IPV6_ADDRESS_LENGTH ? AF_INET6
121                                                                                                           : AF_INET;
122 
123   if (si91x_client_socket->remote_address.sin6_family == AF_INET6) {
124     memcpy(si91x_client_socket->remote_address.sin6_addr.s6_addr,
125            accept_response->dest_ip_addr.ipv6_address,
126            SL_IPV6_ADDRESS_LENGTH);
127 
128   } else {
129     memcpy(&((struct sockaddr_in *)&si91x_client_socket->remote_address)->sin_addr,
130            accept_response->dest_ip_addr.ipv4_address,
131            SL_IPV4_ADDRESS_LENGTH);
132   }
133 }
134 
handle_select_response(const sl_si91x_socket_select_rsp_t * response,sl_si91x_fd_set * readfds,sl_si91x_fd_set * writefds,sl_si91x_fd_set * exception_fd)135 int handle_select_response(const sl_si91x_socket_select_rsp_t *response,
136                            sl_si91x_fd_set *readfds,
137                            sl_si91x_fd_set *writefds,
138                            sl_si91x_fd_set *exception_fd)
139 {
140   // To track of the total number of file descriptors set
141   int total_fd_set_count = 0;
142 
143   // Clear file descriptor sets
144   SLI_SI91X_NULL_SAFE_FD_ZERO(readfds);
145   SLI_SI91X_NULL_SAFE_FD_ZERO(writefds);
146   SLI_SI91X_NULL_SAFE_FD_ZERO(exception_fd);
147 
148   // Iterate through all host sockets
149   for (int host_socket_index = 0; host_socket_index < NUMBER_OF_SOCKETS; host_socket_index++) {
150     const sli_si91x_socket_t *socket = get_si91x_socket(host_socket_index);
151     //Verifying socket existence
152     if (socket == NULL) {
153       continue;
154     }
155 
156     // Check if the read file descriptor set is provided and if the corresponding bit is set in the response
157     if (readfds != NULL && (response->read_fds.fd_array[0] & (1 << socket->id))) {
158       SL_SI91X_FD_SET(host_socket_index, readfds);
159       total_fd_set_count++;
160     }
161 
162     // Check if the write file descriptor set is provided and if the corresponding bit is set in the response.
163     if (writefds != NULL && (response->write_fds.fd_array[0] & (1 << socket->id))) {
164       SL_SI91X_FD_SET(host_socket_index, writefds);
165       total_fd_set_count++;
166     }
167   }
168 
169   return total_fd_set_count;
170 }
171 
sli_si91x_set_accept_callback(sli_si91x_socket_t * server_socket,sl_si91x_socket_accept_callback_t callback,int32_t client_socket_id)172 void sli_si91x_set_accept_callback(sli_si91x_socket_t *server_socket,
173                                    sl_si91x_socket_accept_callback_t callback,
174                                    int32_t client_socket_id)
175 {
176   // Set the user-defined accept callback function and the client socket ID
177   server_socket->user_accept_callback = callback;
178   server_socket->client_id            = client_socket_id;
179 }
180 
sli_si91x_set_remote_socket_termination_callback(sl_si91x_socket_remote_termination_callback_t callback)181 void sli_si91x_set_remote_socket_termination_callback(sl_si91x_socket_remote_termination_callback_t callback)
182 {
183   user_remote_socket_termination_callback = callback;
184 }
185 
sli_si91x_socket_init(uint8_t max_select_count)186 sl_status_t sli_si91x_socket_init(uint8_t max_select_count)
187 {
188   // Check if the mutex for socket operations is already initialized.
189   // If not, create a new mutex to ensure thread-safe access.
190   if (sli_si91x_socket_mutex == NULL) {
191     sli_si91x_socket_mutex = osMutexNew(NULL); // Create a new mutex.
192     if (sli_si91x_socket_mutex == NULL) {
193       return SL_STATUS_FAIL; // Return failure if mutex creation fails.
194     }
195   }
196 
197   // Check if the event flags object for socket events is already initialized.
198   // If not, create a new event flag set to manage socket events.
199   if (si91x_socket_events == NULL) {
200     si91x_socket_events = osEventFlagsNew(NULL); // Create new event flags.
201     if (si91x_socket_events == NULL) {
202       return SL_STATUS_FAIL; // Return failure if event flag creation fails.
203     }
204   }
205 
206   // Check if the event flags object for socket select events is already initialized.
207   // If not, create a new event flag set to manage socket select events.
208   if (si91x_socket_select_events == NULL) {
209     si91x_socket_select_events = osEventFlagsNew(NULL); // Create new event flags.
210     if (si91x_socket_select_events == NULL) {
211       return SL_STATUS_FAIL; // Return failure if event flag creation fails.
212     }
213   }
214 
215   /*
216   Allocate memory for the select request table based on the number of select instances.
217   Heap memory is allocated for the number of instances of this structure based on
218   the number of selects configured by the user during device initialization in opermode.
219   Each time a sync or async select command is sent to the firmware, the corresponding
220   structure is updated, and the instance is cleared when the response is received.
221   */
222 
223   // Check if the select_request_table is uninitialized and max_select_count is valid.
224   if (select_request_table == NULL && max_select_count != 0 && max_select_count <= 10) {
225     sli_si91x_max_select_count = max_select_count; // Store the max number of selects.
226 
227     // Allocate memory for the select request table based on the max_select_count.
228     select_request_table = calloc(max_select_count, sizeof(sli_si91x_select_request_t));
229 
230     // If memory allocation fails, return failure.
231     if (select_request_table == NULL) {
232       return SL_STATUS_FAIL; // Return failure if memory allocation fails.
233     }
234   }
235 
236   return SL_STATUS_OK; // Return success if initialization is successful.
237 }
238 
sli_si91x_socket_deinit(void)239 sl_status_t sli_si91x_socket_deinit(void)
240 {
241   // free the sli_si91x_socket_mutex
242   if (sli_si91x_socket_mutex != NULL) {
243     osMutexDelete(sli_si91x_socket_mutex);
244     sli_si91x_socket_mutex = NULL;
245   }
246   if (si91x_socket_events != NULL) {
247     osEventFlagsDelete(si91x_socket_events);
248     si91x_socket_events = NULL;
249   }
250   if (si91x_socket_select_events != NULL) {
251     osEventFlagsDelete(si91x_socket_select_events);
252     si91x_socket_select_events = NULL;
253   }
254   if (select_request_table != NULL) {
255     free(select_request_table);
256     select_request_table = NULL;
257   }
258   return SL_STATUS_OK;
259 }
260 
sli_si91x_vap_shutdown(uint8_t vap_id)261 sl_status_t sli_si91x_vap_shutdown(uint8_t vap_id)
262 {
263   // Iterate through all BSD sockets and modify the state to DISCONNECTED those associated with the given VAP ID
264   for (uint8_t socket_index = 0; socket_index < NUMBER_OF_SOCKETS; socket_index++) {
265     if ((sli_si91x_sockets[socket_index] != NULL) && (sli_si91x_sockets[socket_index]->vap_id == vap_id)) {
266       sli_si91x_sockets[socket_index]->state = DISCONNECTED;
267     }
268   }
269 
270   return SL_STATUS_OK;
271 }
272 
sli_si91x_handle_websocket(sl_si91x_socket_create_request_t * socket_create_request,const sli_si91x_socket_t * si91x_bsd_socket)273 void sli_si91x_handle_websocket(sl_si91x_socket_create_request_t *socket_create_request,
274                                 const sli_si91x_socket_t *si91x_bsd_socket)
275 {
276   socket_create_request->ssl_bitmap |= SI91X_WEBSOCKET_FEAT;
277 
278   // Copy host name
279   if (si91x_bsd_socket->websocket_info && si91x_bsd_socket->websocket_info->host_length > 0) {
280     memcpy(socket_create_request->webs_host_name,
281            si91x_bsd_socket->websocket_info->websocket_data,
282            si91x_bsd_socket->websocket_info->host_length);
283     socket_create_request->webs_host_name[si91x_bsd_socket->websocket_info->host_length] = '\0'; // Null-terminate
284   }
285 
286   // Copy resource name
287   if (si91x_bsd_socket->websocket_info && si91x_bsd_socket->websocket_info->resource_length > 0) {
288     memcpy(socket_create_request->webs_resource_name,
289            si91x_bsd_socket->websocket_info->websocket_data + si91x_bsd_socket->websocket_info->host_length,
290            si91x_bsd_socket->websocket_info->resource_length);
291     socket_create_request->webs_resource_name[si91x_bsd_socket->websocket_info->resource_length] =
292       '\0'; // Null-terminate
293   }
294 }
295 
sl_si91x_config_socket(sl_si91x_socket_config_t socket_config)296 sl_status_t sl_si91x_config_socket(sl_si91x_socket_config_t socket_config)
297 {
298   sl_status_t status = SL_STATUS_OK;
299 
300   // Send the socket configuration command to the SI91X driver
301   status = sl_si91x_driver_send_command(RSI_WLAN_REQ_SOCKET_CONFIG,
302                                         SI91X_SOCKET_CMD,
303                                         &socket_config,
304                                         sizeof(socket_config),
305                                         SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
306                                         NULL,
307                                         NULL);
308 
309   VERIFY_STATUS_AND_RETURN(status);
310   return status;
311 }
312 
reset_socket_state(int socket)313 void reset_socket_state(int socket)
314 {
315   if (sli_si91x_sockets[socket] == NULL) {
316     return;
317   }
318 
319   if (sli_si91x_sockets[socket]->socket_events != NULL) {
320     osEventFlagsDelete(sli_si91x_sockets[socket]->socket_events);
321     sli_si91x_sockets[socket]->socket_events = NULL;
322   }
323 
324   free(sli_si91x_sockets[socket]);
325   sli_si91x_sockets[socket] = NULL;
326 }
327 
328 // Get the SI91X socket with the specified index, if it is valid and not in RESET state
get_si91x_socket(int32_t socket)329 sli_si91x_socket_t *get_si91x_socket(int32_t socket)
330 {
331   if (socket < 0 || socket >= NUMBER_OF_SOCKETS) {
332     return NULL;
333   }
334   return sli_si91x_sockets[socket];
335 }
336 
sli_si91x_get_socket_from_id(int socket_id,sli_si91x_bsd_socket_state_t excluded_state,int16_t role)337 sli_si91x_socket_t *sli_si91x_get_socket_from_id(int socket_id,
338                                                  sli_si91x_bsd_socket_state_t excluded_state,
339                                                  int16_t role)
340 {
341   sli_si91x_socket_t *possible_socket = NULL;
342   for (uint8_t index = 0; index < NUMBER_OF_SOCKETS; ++index) {
343     sli_si91x_socket_t *socket = sli_si91x_sockets[index];
344     if (socket != NULL && socket->id == socket_id && socket->state != excluded_state
345         && (role == -1 || socket->role == role)) {
346       if (socket->command_queue.command_in_flight == false) {
347         possible_socket = socket;
348       } else {
349         return socket;
350       }
351     }
352   }
353   return possible_socket;
354 }
355 
sli_si91x_get_socket_from_port(uint16_t src_port)356 static sli_si91x_socket_t *sli_si91x_get_socket_from_port(uint16_t src_port)
357 {
358   for (int i = 0; i < NUMBER_OF_SOCKETS; i++) {
359     if (sli_si91x_sockets[i] == NULL) {
360       continue;
361     }
362     if ((sli_si91x_sockets[i]->role == SI91X_SOCKET_TCP_SERVER)
363         && (src_port == sli_si91x_sockets[i]->local_address.sin6_port)) {
364       return sli_si91x_sockets[i];
365     }
366   }
367 
368   return NULL;
369 }
370 
371 // Find and return an available socket and its index
get_free_socket(sli_si91x_socket_t ** socket,int * socket_fd)372 void get_free_socket(sli_si91x_socket_t **socket, int *socket_fd)
373 {
374   *socket    = NULL;
375   *socket_fd = -1;
376 
377   osMutexAcquire(sli_si91x_socket_mutex, 0xFFFFFFFFUL);
378   // Iterate through all available sockets to find a free one
379   for (uint8_t socket_index = 0; socket_index < NUMBER_OF_SOCKETS; socket_index++) {
380 
381     // If the socket is in use skip it
382     if (sli_si91x_sockets[socket_index] != NULL) {
383       continue;
384     }
385 
386     // Allocate new socket
387     sli_si91x_sockets[socket_index] = malloc(sizeof(sli_si91x_socket_t));
388     if (sli_si91x_sockets[socket_index] == NULL) {
389       break;
390     }
391     memset(sli_si91x_sockets[socket_index], 0, sizeof(sli_si91x_socket_t));
392     sli_si91x_sockets[socket_index]->id                = -1;
393     sli_si91x_sockets[socket_index]->index             = socket_index;
394     sli_si91x_sockets[socket_index]->data_buffer_limit = SL_SOCKET_DEFAULT_BUFFER_LIMIT;
395 
396     // If a free socket is found, set the socket pointer to point to it
397     *socket = sli_si91x_sockets[socket_index];
398     // Set the socket_fd to the index of the free socket, which can be used as a file descriptor
399     *socket_fd = socket_index;
400     // Exit the loop because a free socket has been found.
401     break;
402   }
403   osMutexRelease(sli_si91x_socket_mutex);
404 }
405 
is_port_available(uint16_t port_number)406 static bool is_port_available(uint16_t port_number)
407 {
408   // Check whether local port is already used or not
409   for (uint8_t socket_index = 0; socket_index < NUMBER_OF_SOCKETS; socket_index++) {
410     if (sli_si91x_sockets[socket_index] != NULL
411         && sli_si91x_sockets[socket_index]->local_address.sin6_port == port_number) {
412       return false;
413     }
414   }
415 
416   return true;
417 }
418 
419 /**
420  * @brief This function is responsible to copy the TLS extension information provided by application into socket structure.
421  *
422  * @param socket_tls_extensions pointer to TLS extension in socket structure
423  * @param tls_extension pointer to the TLS information provided by application
424  * @return sl_status_t possible return values are SL_STATUS_OK and SL_STATUS_SI91X_MEMORY_ERROR
425  */
sli_si91x_add_tls_extension(sli_si91x_tls_extensions_t * socket_tls_extensions,const sl_si91x_socket_type_length_value_t * tls_extension)426 sl_status_t sli_si91x_add_tls_extension(sli_si91x_tls_extensions_t *socket_tls_extensions,
427                                         const sl_si91x_socket_type_length_value_t *tls_extension)
428 {
429   // To check if memory available for new extension in buffer of socket, max 256 Bytes only
430   if (SI91X_MAX_SIZE_OF_EXTENSION_DATA - socket_tls_extensions->current_size_of_extensions
431       < (int)(sizeof(sl_si91x_socket_type_length_value_t) + tls_extension->length)) {
432     return SL_STATUS_SI91X_MEMORY_ERROR;
433   }
434 
435   uint8_t extension_size = (uint8_t)(sizeof(sl_si91x_socket_type_length_value_t) + tls_extension->length);
436 
437   // copies TLS extension provided by app into SDK socket struct
438   memcpy(&socket_tls_extensions->buffer[socket_tls_extensions->current_size_of_extensions],
439          tls_extension,
440          extension_size);
441   socket_tls_extensions->current_size_of_extensions += extension_size;
442   socket_tls_extensions->total_extensions++;
443 
444   return SL_STATUS_OK;
445 }
446 
sli_get_socket_command_from_host_packet(sl_wifi_buffer_t * buffer)447 int32_t sli_get_socket_command_from_host_packet(sl_wifi_buffer_t *buffer)
448 {
449   sl_si91x_packet_t *packet = (sl_si91x_packet_t *)buffer->data;
450   return (packet == NULL ? -1 : packet->command);
451 }
452 
453 // Prepare socket request based on socket type and send the request down to the driver.
454 // socket type : [SL_SOCKET_TCP_SERVER, SL_SOCKET_TCP_CLIENT, SL_SOCKET_LUDP, SL_SOCKET_UDP_CLIENT]
create_and_send_socket_request(int socketIdIndex,int type,const int * backlog)455 sl_status_t create_and_send_socket_request(int socketIdIndex, int type, const int *backlog)
456 {
457   sl_status_t status                                              = SL_STATUS_OK;
458   sl_si91x_socket_create_request_t socket_create_request          = { 0 };
459   const sl_si91x_socket_create_response_t *socket_create_response = NULL;
460   sli_si91x_socket_t *si91x_bsd_socket                            = get_si91x_socket(socketIdIndex);
461   sl_si91x_wait_period_t wait_period                              = SL_SI91X_WAIT_FOR_RESPONSE(5000);
462   //Verifying socket existence
463   if (si91x_bsd_socket == NULL) {
464     return -1;
465   }
466   if (type == SI91X_SOCKET_TCP_CLIENT) {
467     wait_period = SL_SI91X_WAIT_FOR_RESPONSE(100000); // timeout is 10 sec
468   }
469 
470   sl_wifi_buffer_t *buffer  = NULL;
471   sl_si91x_packet_t *packet = NULL;
472 
473   if (si91x_bsd_socket->local_address.sin6_family == AF_INET6) {
474     socket_create_request.ip_version = SL_IPV6_VERSION;
475 
476     memcpy(socket_create_request.dest_ip_addr.ipv6_address,
477            si91x_bsd_socket->remote_address.sin6_addr.s6_addr,
478            SL_IPV6_ADDRESS_LENGTH);
479   } else {
480     socket_create_request.ip_version = SL_IPV4_ADDRESS_LENGTH;
481     memcpy(socket_create_request.dest_ip_addr.ipv4_address,
482            &((struct sockaddr_in *)&si91x_bsd_socket->remote_address)->sin_addr,
483            SL_IPV4_ADDRESS_LENGTH);
484   }
485 
486   socket_create_request.local_port  = si91x_bsd_socket->local_address.sin6_port;
487   socket_create_request.remote_port = si91x_bsd_socket->remote_address.sin6_port;
488 
489   // Fill socket type
490   socket_create_request.socket_type = (uint16_t)type;
491 
492   if (type == SI91X_SOCKET_TCP_SERVER) {
493     socket_create_request.max_count = (backlog == NULL) ? 0 : (uint16_t)*backlog;
494     socket_create_request.socket_bitmap |= SI91X_SOCKET_FEAT_LTCP_ACCEPT;
495     si91x_bsd_socket->socket_events = osEventFlagsNew(NULL);
496   } else {
497     socket_create_request.max_count = 0;
498   }
499 
500   if (si91x_bsd_socket->recv_data_callback == NULL) {
501     socket_create_request.socket_bitmap |= SI91X_SOCKET_FEAT_SYNCHRONOUS;
502   }
503 
504   socket_create_request.socket_bitmap |= SI91X_SOCKET_FEAT_TCP_RX_WINDOW;
505 
506   // Set the RX window size
507   socket_create_request.rx_window_size = TCP_RX_WINDOW_SIZE;
508 
509   // Fill VAP_ID
510   socket_create_request.vap_id                = si91x_bsd_socket->vap_id;
511   socket_create_request.tos                   = 0;
512   socket_create_request.max_tcp_retries_count = si91x_bsd_socket->max_tcp_retries ? si91x_bsd_socket->max_tcp_retries
513                                                                                   : MAX_TCP_RETRY_COUNT;
514   socket_create_request.tcp_keepalive_initial_time = si91x_bsd_socket->tcp_keepalive_initial_time
515                                                        ? si91x_bsd_socket->tcp_keepalive_initial_time
516                                                        : DEFAULT_TCP_KEEP_ALIVE_TIME;
517   socket_create_request.tcp_mss                    = si91x_bsd_socket->mss;
518 
519   // Check for SSL feature and fill it in SSL bitmap
520   if (si91x_bsd_socket->ssl_bitmap & SL_SI91X_ENABLE_TLS) {
521     socket_create_request.ssl_bitmap         = si91x_bsd_socket->ssl_bitmap;
522     socket_create_request.ssl_ciphers_bitmap = SSL_ALL_CIPHERS;
523 #if defined(SLI_SI917) || defined(SLI_SI915)
524     socket_create_request.ssl_ext_ciphers_bitmap = SSL_EXT_CIPHERS;
525 #endif
526     // Check if cert index is not default index
527     if (si91x_bsd_socket->certificate_index > SI91X_CERT_INDEX_0) {
528       socket_create_request.socket_bitmap |= SI91X_SOCKET_FEAT_CERT_INDEX;
529     }
530 
531     socket_create_request.socket_cert_inx = si91x_bsd_socket->certificate_index;
532 
533     // Check if extension is provided my application and memcopy until the provided size of extensions
534     if (si91x_bsd_socket->tls_extensions.total_extensions > 0) {
535       memcpy(socket_create_request.tls_extension_data,
536              si91x_bsd_socket->tls_extensions.buffer,
537              si91x_bsd_socket->tls_extensions.current_size_of_extensions);
538 
539       socket_create_request.total_extension_length = si91x_bsd_socket->tls_extensions.current_size_of_extensions;
540       socket_create_request.no_of_tls_extensions   = si91x_bsd_socket->tls_extensions.total_extensions;
541     }
542     wait_period = SL_SI91X_WAIT_FOR_RESPONSE(150000); // timeout is 15 sec
543   }
544 
545   // Check for HIGH_PERFORMANCE feature bit
546   if (si91x_bsd_socket->ssl_bitmap & SI91X_HIGH_PERFORMANCE_SOCKET) {
547     socket_create_request.ssl_bitmap |= SI91X_HIGH_PERFORMANCE_SOCKET;
548   }
549 
550   // Check for Websocket feature bit
551   if (si91x_bsd_socket->ssl_bitmap & SI91X_WEBSOCKET_FEAT) {
552     sli_si91x_handle_websocket(&socket_create_request, si91x_bsd_socket);
553   }
554 
555   // Check for TCP ACK INDICATION feature bit
556   if (si91x_bsd_socket->socket_bitmap & SI91X_SOCKET_FEAT_TCP_ACK_INDICATION) {
557     socket_create_request.socket_bitmap |= SI91X_SOCKET_FEAT_TCP_ACK_INDICATION;
558   }
559 #if defined(SLI_SI917) || defined(SLI_SI915)
560   // Set socket's max retransmission timeout value and TOS (Type of Service) if applicable
561   socket_create_request.max_retransmission_timeout_value = (uint8_t)si91x_bsd_socket->max_retransmission_timeout_value;
562   socket_create_request.tos                              = (uint16_t)si91x_bsd_socket->tos;
563 #endif
564 
565   // Store socket role for future references.
566   si91x_bsd_socket->role = type;
567   status                 = sl_si91x_driver_send_command(RSI_WLAN_REQ_SOCKET_CREATE,
568                                         SI91X_SOCKET_CMD,
569                                         &socket_create_request,
570                                         sizeof(socket_create_request),
571                                         wait_period,
572                                         NULL,
573                                         &buffer);
574 
575   // If the status is not OK and there's a buffer, free the buffer
576   if ((status != SL_STATUS_OK) && (buffer != NULL)) {
577     sl_si91x_host_free_buffer(buffer);
578   }
579   VERIFY_STATUS_AND_RETURN(status);
580 
581   // Extract socket creation response information
582   packet                 = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
583   socket_create_response = (sl_si91x_socket_create_response_t *)packet->data;
584 
585   si91x_bsd_socket->id = (int32_t)(socket_create_response->socket_id[0] | (socket_create_response->socket_id[1] << 8));
586   si91x_bsd_socket->local_address.sin6_port =
587     (uint16_t)(socket_create_response->module_port[0] | (socket_create_response->module_port[1] << 8));
588 
589   if (type != SI91X_SOCKET_TCP_SERVER) {
590     si91x_bsd_socket->remote_address.sin6_port =
591       (uint16_t)(socket_create_response->dst_port[0] | socket_create_response->dst_port[1] << 8);
592   }
593 
594   si91x_bsd_socket->mss = (uint16_t)((socket_create_response->mss[0]) | (socket_create_response->mss[1] << 8));
595 
596   // If socket is already bound to an local address and port, there is no need to copy it again.
597   if (si91x_bsd_socket->state == BOUND) {
598     sl_si91x_host_free_buffer(buffer);
599     return SL_STATUS_OK;
600   }
601 
602   // Copy the local address (IPv4 or IPv6) based on family type
603   if (si91x_bsd_socket->local_address.sin6_family == AF_INET) {
604     memcpy(&((struct sockaddr_in *)&si91x_bsd_socket->local_address)->sin_addr.s_addr,
605            socket_create_response->module_ip_addr.ipv4_addr,
606            SL_IPV4_ADDRESS_LENGTH);
607   } else {
608     memcpy(si91x_bsd_socket->local_address.sin6_addr.s6_addr,
609            socket_create_response->module_ip_addr.ipv6_addr,
610            SL_IPV6_ADDRESS_LENGTH);
611   }
612 
613   // Free the buffer
614   sl_si91x_host_free_buffer(buffer);
615 
616   return SL_STATUS_OK;
617 }
618 
sli_si91x_socket(int family,int type,int protocol,sl_si91x_socket_receive_data_callback_t callback)619 int sli_si91x_socket(int family, int type, int protocol, sl_si91x_socket_receive_data_callback_t callback)
620 {
621   // Validate the socket parameters
622   SET_ERRNO_AND_RETURN_IF_TRUE(family != AF_INET && family != AF_INET6, EAFNOSUPPORT);
623   SET_ERRNO_AND_RETURN_IF_TRUE(type != SOCK_STREAM && type != SOCK_DGRAM, EINVAL);
624   SET_ERRNO_AND_RETURN_IF_TRUE(protocol != IPPROTO_TCP && protocol != IPPROTO_UDP && protocol != 0, EINVAL);
625   SET_ERRNO_AND_RETURN_IF_TRUE((type == SOCK_STREAM && (protocol != IPPROTO_TCP && protocol != 0)), EPROTOTYPE);
626   SET_ERRNO_AND_RETURN_IF_TRUE((type == SOCK_DGRAM && (protocol != IPPROTO_UDP && protocol != 0)), EPROTOTYPE);
627 
628   // Initialize a new socket structure
629   sli_si91x_socket_t *si91x_socket;
630   int socket_index = -1;
631 
632   get_free_socket(&si91x_socket, &socket_index);
633 
634   // Check if there is enough memory to create the socket
635   if (socket_index < 0) {
636     SET_ERROR_AND_RETURN(ENOMEM);
637   }
638 
639   // Populate the socket structure with provided parameters and callbacks
640   si91x_socket->type                      = type;
641   si91x_socket->local_address.sin6_family = (uint8_t)family;
642   si91x_socket->protocol                  = protocol;
643   si91x_socket->state                     = INITIALIZED;
644   si91x_socket->recv_data_callback        = callback;
645 
646   // Return the socket index
647   return socket_index;
648 }
649 
sli_si91x_accept(int socket,struct sockaddr * addr,socklen_t * addr_len,sl_si91x_socket_accept_callback_t callback)650 int sli_si91x_accept(int socket, struct sockaddr *addr, socklen_t *addr_len, sl_si91x_socket_accept_callback_t callback)
651 {
652   sl_status_t status                              = SL_STATUS_OK;
653   sli_si91x_socket_t *si91x_client_socket         = NULL;
654   sli_si91x_socket_t *si91x_server_socket         = get_si91x_socket(socket);
655   sl_si91x_socket_accept_request_t accept_request = { 0 };
656   int32_t client_socket_id                        = -1;
657   sl_wifi_buffer_t *buffer                        = NULL;
658 
659   // Check if the server socket is valid
660   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_server_socket == NULL, EBADF);
661   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_server_socket->type != SOCK_STREAM, EOPNOTSUPP);
662   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_server_socket->state != LISTEN, EINVAL);
663 
664   // Create a new instance for socket
665   client_socket_id = sli_si91x_socket(si91x_server_socket->local_address.sin6_family,
666                                       si91x_server_socket->type,
667                                       si91x_server_socket->protocol,
668                                       si91x_server_socket->recv_data_callback);
669 
670   si91x_client_socket = get_si91x_socket(client_socket_id);
671   //Verifying socket existence
672   if (si91x_client_socket == NULL)
673     return -1;
674   memcpy(&si91x_client_socket->local_address, &si91x_server_socket->local_address, sizeof(struct sockaddr_in6));
675 
676   // Create accept request
677   accept_request.socket_id   = (uint8_t)si91x_server_socket->id;
678   accept_request.source_port = si91x_server_socket->local_address.sin6_port;
679 
680   // Set the callback and client socket ID.
681   sli_si91x_set_accept_callback(si91x_server_socket, callback, client_socket_id);
682   if (callback != NULL) {
683     status = sli_si91x_send_socket_command(si91x_client_socket,
684                                            RSI_WLAN_REQ_SOCKET_ACCEPT,
685                                            &accept_request,
686                                            sizeof(accept_request),
687                                            SL_SI91X_RETURN_IMMEDIATELY,
688                                            NULL);
689     SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
690     return SL_STATUS_OK;
691   } else {
692     status = sli_si91x_send_socket_command(si91x_client_socket,
693                                            RSI_WLAN_REQ_SOCKET_ACCEPT,
694                                            &accept_request,
695                                            sizeof(accept_request),
696                                            SL_SI91X_WAIT_FOR_EVER | SL_SI91X_WAIT_FOR_RESPONSE_BIT,
697                                            &buffer);
698     SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
699   }
700 
701   // If the accept request fails, clean up allocated memory and return an error
702   if (status != SL_STATUS_OK) {
703     sli_si91x_shutdown(client_socket_id, SHUTDOWN_BY_ID);
704     if (buffer != NULL) {
705       sl_si91x_host_free_buffer(buffer);
706     }
707     SET_ERROR_AND_RETURN(SI91X_UNDEFINED_ERROR);
708   }
709 
710   sli_si91x_queue_packet_t *node = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
711   sl_wifi_buffer_t *response     = node->host_packet;
712   sl_si91x_host_free_buffer(buffer);
713 
714   if (response == NULL) {
715     SET_ERROR_AND_RETURN(SI91X_UNDEFINED_ERROR);
716   }
717 
718   sl_si91x_packet_t *packet     = sl_si91x_host_get_buffer_data(response, 0, NULL);
719   sl_si91x_rsp_ltcp_est_t *ltcp = (sl_si91x_rsp_ltcp_est_t *)packet->data;
720 
721   handle_accept_response(si91x_client_socket, ltcp);
722 
723   // If addr_len is NULL or invalid value, just return the client socket ID
724   if (addr != NULL && *addr_len > 0) {
725     // Copy the remote address to the provided sockaddr structure
726     memcpy(addr,
727            &si91x_client_socket->remote_address,
728            (*addr_len > sizeof(struct sockaddr_in6)) ? sizeof(struct sockaddr_in6) : *addr_len);
729 
730     // Update addr_len based on the family of the local address
731     *addr_len = si91x_client_socket->local_address.sin6_family == AF_INET ? sizeof(struct sockaddr_in)
732                                                                           : sizeof(struct sockaddr_in6);
733   }
734   // Free resources and return the client socket ID
735   sl_si91x_host_free_buffer(response);
736 
737   return client_socket_id;
738 }
739 
740 // Shutdown a socket
sli_si91x_shutdown(int socket,int how)741 int sli_si91x_shutdown(int socket, int how)
742 {
743   sl_status_t status                                      = SL_STATUS_OK;
744   sl_si91x_socket_close_request_t socket_close_request    = { 0 };
745   sl_si91x_socket_close_response_t *socket_close_response = NULL;
746   sl_si91x_wait_period_t wait_period                      = SL_SI91X_WAIT_FOR_RESPONSE(SL_SI91X_WAIT_FOR_EVER);
747   sl_wifi_buffer_t *buffer                                = NULL;
748 
749   sli_si91x_socket_t *si91x_socket = get_si91x_socket(socket);
750 
751   // Verify the socket's existence
752   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
753 
754   // The firmware maps server socket and first client socket connected to the server would be assigned same firmware socket ID.
755   // Therefore, if Dev attempts to close either first client or server, close request type needs to be set to SHUTDOWN_BY_PORT.
756   int close_request_type = (si91x_socket->state == LISTEN) ? SHUTDOWN_BY_PORT : how;
757 
758   // If the socket is in an initial state or marked for auto-close, reset it and return
759   if (si91x_socket->state == BOUND || si91x_socket->state == INITIALIZED
760       || (si91x_socket->state == DISCONNECTED && is_tcp_auto_close_enabled())) {
761     reset_socket_state(socket);
762 
763     return SI91X_NO_ERROR;
764   }
765 
766   /*If socket is server socket, SHUTDOWN_BY_PORT is to be used irrespective of 'how' parameter.*/
767   socket_close_request.socket_id   = (uint16_t)((close_request_type == SHUTDOWN_BY_ID) ? si91x_socket->id : 0);
768   socket_close_request.port_number = (close_request_type == SHUTDOWN_BY_ID) ? 0 : si91x_socket->local_address.sin6_port;
769 
770   status = sli_si91x_send_socket_command(si91x_socket,
771                                          RSI_WLAN_REQ_SOCKET_CLOSE,
772                                          &socket_close_request,
773                                          sizeof(socket_close_request),
774                                          wait_period,
775                                          &buffer);
776 
777   // If the status is not OK and there's a buffer, free the buffer
778   if ((status != SL_STATUS_OK) && (buffer != NULL)) {
779     sl_si91x_host_free_buffer(buffer);
780   }
781   SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
782 
783   sli_si91x_queue_packet_t *node = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
784   if (node->host_packet == NULL) {
785     sl_si91x_host_free_buffer(buffer);
786     return SL_STATUS_FAIL;
787   }
788 
789   sl_wifi_buffer_t *response_buffer = node->host_packet;
790   sl_si91x_host_free_buffer(buffer);
791 
792   sl_si91x_packet_t *packet = sl_si91x_host_get_buffer_data(response_buffer, 0, NULL);
793   socket_close_response     = (sl_si91x_socket_close_response_t *)packet->data;
794 
795   if (close_request_type == SHUTDOWN_BY_ID && si91x_socket->id == socket_close_response->socket_id) {
796     reset_socket_state(socket);
797     sl_si91x_host_free_buffer(response_buffer);
798     return SI91X_NO_ERROR;
799   }
800   // Reset sockets that match the close request
801   for (uint8_t index = 0; index < NUMBER_OF_SOCKETS; index++) {
802     const sli_si91x_socket_t *socket_id = get_si91x_socket(index);
803     //Verifying socket existence
804     if (socket_id == NULL)
805       continue;
806     else if (close_request_type == SHUTDOWN_BY_PORT
807              && socket_id->local_address.sin6_port == socket_close_response->port_number) {
808       reset_socket_state(index);
809     }
810   }
811 
812   sl_si91x_host_free_buffer(response_buffer);
813 
814   return SI91X_NO_ERROR;
815 }
816 
si91x_socket_event_handler(sl_status_t status,sl_si91x_socket_context_t * sdk_context,sl_si91x_packet_t * rx_packet)817 sl_status_t si91x_socket_event_handler(sl_status_t status,
818                                        sl_si91x_socket_context_t *sdk_context,
819                                        sl_si91x_packet_t *rx_packet)
820 {
821   UNUSED_PARAMETER(status);
822 
823   // Handle connection establishment response
824   if (rx_packet->command == RSI_WLAN_REQ_SOCKET_ACCEPT) {
825     const sl_si91x_rsp_ltcp_est_t *accept_response = (sl_si91x_rsp_ltcp_est_t *)rx_packet->data;
826     sli_si91x_socket_t *server_socket              = sli_si91x_get_socket_from_port(accept_response->src_port_num);
827     int32_t client_socket_id                       = -1;
828     if (server_socket == NULL) {
829       return -1;
830     }
831     client_socket_id                  = server_socket->client_id;
832     server_socket->client_id          = -1;
833     sli_si91x_socket_t *client_socket = get_si91x_socket(client_socket_id);
834 
835     handle_accept_response(client_socket, accept_response);
836 
837     if (server_socket->user_accept_callback != NULL) {
838       // Call the accept callback function with relevant socket information
839       server_socket->user_accept_callback(client_socket_id,
840                                           (struct sockaddr *)&server_socket->remote_address,
841                                           (uint8_t)server_socket->type);
842     }
843   }
844   // Handle remote socket termination response
845   else if (rx_packet->command == RSI_WLAN_RSP_REMOTE_TERMINATE) {
846 
847     sl_si91x_socket_close_response_t *remote_socket_closure = (sl_si91x_socket_close_response_t *)rx_packet->data;
848     // Reset sockets that match the close request
849     for (uint8_t index = 0; index < NUMBER_OF_SOCKETS; index++) {
850       sli_si91x_socket_t *socket = get_si91x_socket(index);
851       //Verifying socket existence
852       if (socket == NULL || remote_socket_closure->socket_id != socket->id || socket->state == LISTEN)
853         continue;
854 
855       socket->state         = DISCONNECTED;
856       uint16_t frame_status = get_si91x_frame_status(rx_packet);
857       sli_si91x_flush_socket_command_queues_based_on_queue_type(index, frame_status);
858       sli_si91x_flush_socket_data_queues_based_on_queue_type(index);
859 
860       if (user_remote_socket_termination_callback != NULL) {
861         user_remote_socket_termination_callback(socket->id,
862                                                 socket->local_address.sin6_port,
863                                                 remote_socket_closure->sent_bytes_count);
864       }
865       break;
866     }
867   } else if (rx_packet->command == RSI_RECEIVE_RAW_DATA) {
868     // Handle the case when raw data is received
869     const sl_si91x_socket_metadata_t *firmware_socket_response = (sl_si91x_socket_metadata_t *)rx_packet->data;
870     uint8_t *data                                              = (rx_packet->data + firmware_socket_response->offset);
871 
872     int8_t host_socket = -1;
873 
874     // Find the host socket corresponding to the received data
875     for (uint8_t host_socket_index = 0; host_socket_index < NUMBER_OF_SOCKETS; host_socket_index++) {
876       if ((sli_si91x_sockets[host_socket_index] != NULL)
877           && (firmware_socket_response->socket_id == sli_si91x_sockets[host_socket_index]->id)) {
878         host_socket = host_socket_index;
879       }
880     }
881 
882     // Retrieve the client socket
883     const sli_si91x_socket_t *client_socket = get_si91x_socket(host_socket);
884     //Verifying socket existence
885     if (client_socket == NULL) {
886       SL_CLEANUP_MALLOC(sdk_context);
887       return -1;
888     }
889 
890     // Call the user-defined receive data callback
891     client_socket->recv_data_callback(host_socket, data, firmware_socket_response->length, firmware_socket_response);
892   } else if (rx_packet->command == RSI_WLAN_RSP_SELECT_REQUEST) {
893     sl_si91x_socket_select_rsp_t *socket_select_rsp = (sl_si91x_socket_select_rsp_t *)rx_packet->data;
894 
895     if (socket_select_rsp->select_id < sli_si91x_max_select_count
896         && select_request_table[socket_select_rsp->select_id].in_use) {
897       sli_si91x_select_request_t *select_request = &select_request_table[socket_select_rsp->select_id];
898       select_request->frame_status               = (uint16_t)(rx_packet->desc[12] + (rx_packet->desc[13] << 8));
899       if (select_request->select_callback != NULL) {
900         sl_si91x_fd_set read_fd;
901         sl_si91x_fd_set write_fd;
902         sl_si91x_fd_set exception_fd;
903 
904         // This function handles responses received from the SI91X socket driver
905         handle_select_response((sl_si91x_socket_select_rsp_t *)rx_packet->data, &read_fd, &write_fd, &exception_fd);
906 
907         // Call the user-defined select callback function with the updated file descriptor sets and status
908         select_request->select_callback(&read_fd, &write_fd, &exception_fd, status);
909 
910         sli_si91x_clear_select_id(select_request->select_id);
911       } else {
912         select_request->response_data = malloc(sizeof(sl_si91x_socket_select_rsp_t));
913         if (select_request->response_data == NULL) {
914           SL_DEBUG_LOG("\r\n HEAP EXHAUSTED DURING ALLOCATION \r\n");
915         } else {
916           memcpy(select_request->response_data, rx_packet->data, sizeof(sl_si91x_socket_select_rsp_t));
917           osEventFlagsSet(si91x_socket_select_events, BIT(socket_select_rsp->select_id));
918         }
919       }
920     } else {
921       SL_DEBUG_LOG("\r\n INVALID SELECT ID\r\n");
922     }
923   }
924   // This block of code is executed when a TCP acknowledgment indication is received.
925   else if (rx_packet->command == RSI_WLAN_RSP_TCP_ACK_INDICATION) {
926     const sl_si91x_rsp_tcp_ack_t *tcp_ack = (sl_si91x_rsp_tcp_ack_t *)rx_packet->data;
927 
928     // Initialize a variable to store the host socket ID
929     int8_t host_socket = -1;
930 
931     // Iterate through all host sockets to find a matching socket ID
932     for (uint8_t host_socket_index = 0; host_socket_index < NUMBER_OF_SOCKETS; host_socket_index++) {
933       if ((sli_si91x_sockets[host_socket_index] != NULL)
934           && (tcp_ack->socket_id == sli_si91x_sockets[host_socket_index]->id)) {
935         host_socket = host_socket_index;
936         break;
937       }
938     }
939     // Retrieve the SI91X socket associated with the host socket
940     sli_si91x_socket_t *si91x_socket = get_si91x_socket(host_socket);
941     //Verifying socket existence
942     if (si91x_socket == NULL) {
943       SL_CLEANUP_MALLOC(sdk_context);
944       return -1;
945     }
946     // Check if the SI91X_SOCKET_FEAT_TCP_ACK_INDICATION bit is set move the socket to CONNECTED state.
947     if (si91x_socket->socket_bitmap & SI91X_SOCKET_FEAT_TCP_ACK_INDICATION) {
948       si91x_socket->is_waiting_on_ack = false;
949     }
950     // Check if the SI91X socket and its data transfer callback function exist
951     if (si91x_socket != NULL && si91x_socket->data_transfer_callback != NULL) {
952       si91x_socket->data_transfer_callback(host_socket, (uint8_t)(tcp_ack->length[0] | tcp_ack->length[1] << 8));
953     }
954   }
955 
956   // Cleanup any dynamically allocated memory in the SDK context
957   SL_CLEANUP_MALLOC(sdk_context);
958 
959   return SL_STATUS_OK;
960 }
961 
sli_si91x_send_socket_command(sli_si91x_socket_t * socket,uint32_t command,const void * data,uint32_t data_length,uint32_t wait_period,sl_wifi_buffer_t ** response_buffer)962 sl_status_t sli_si91x_send_socket_command(sli_si91x_socket_t *socket,
963                                           uint32_t command,
964                                           const void *data,
965                                           uint32_t data_length,
966                                           uint32_t wait_period,
967                                           sl_wifi_buffer_t **response_buffer)
968 
969 {
970   sl_wifi_buffer_t *buffer;
971   sl_si91x_packet_t *packet;
972   sl_wifi_buffer_t *node_buffer;
973   sli_si91x_queue_packet_t *node;
974   sl_status_t status;
975   static uint8_t command_packet_id = 0;
976 
977   // Allocate a buffer for the command with appropriate size
978   status = sli_si91x_allocate_command_buffer(&buffer,
979                                              (void **)&packet,
980                                              sizeof(sl_si91x_packet_t) + data_length,
981                                              SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
982   VERIFY_STATUS_AND_RETURN(status);
983 
984   // Allocate a queue node
985   status = sli_si91x_allocate_command_buffer(&node_buffer,
986                                              (void **)&node,
987                                              sizeof(sli_si91x_queue_packet_t),
988                                              SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
989   if (status != SL_STATUS_OK) {
990     sl_si91x_host_free_buffer(buffer);
991     return status;
992   }
993 
994   // Clear the packet descriptor and copy the command data if available
995   memset(packet->desc, 0, sizeof(packet->desc));
996   if (data != NULL) {
997     memcpy(packet->data, data, data_length);
998   }
999 
1000   // Fill frame type
1001   packet->length  = data_length & 0xFFF;
1002   packet->command = command;
1003 
1004   // Set flags
1005 #ifdef TEST_USE_UNUSED_FLAGS
1006   packet->unused[SLI_SI91X_COMMAND_FLAGS_INDEX] = (wait_period & SL_SI91X_WAIT_FOR_RESPONSE_BIT) ? (1 << 0) : 0;
1007   packet->unused[SLI_SI91X_COMMAND_FLAGS_INDEX] |= (response_buffer == NULL) ? (1 << 1) : 0;
1008   if (command == RSI_WLAN_REQ_SOCKET_ACCEPT) {
1009     packet->unused[SLI_SI91X_COMMAND_RESPONSE_INDEX] = RSI_WLAN_RSP_CONN_ESTABLISH;
1010   } else {
1011     packet->unused[SLI_SI91X_COMMAND_RESPONSE_INDEX] = command;
1012   }
1013 #else
1014   node->flags = (wait_period & SL_SI91X_WAIT_FOR_RESPONSE_BIT) ? SI91X_PACKET_RESPONSE_PACKET : 0;
1015 #endif
1016 
1017   wait_period &= ~SL_SI91X_WAIT_FOR_RESPONSE_BIT;
1018 
1019   if (wait_period != 0) {
1020     node->flags |= SI91X_PACKET_RESPONSE_STATUS;
1021   }
1022 
1023   // Set various properties of the node representing the command packet
1024   node->host_packet       = buffer;
1025   node->firmware_queue_id = RSI_WLAN_MGMT_Q;
1026   node->command_type      = SI91X_SOCKET_CMD;
1027 
1028   if ((node->flags != SI91X_PACKET_WITH_ASYNC_RESPONSE)) {
1029     node->command_tickcount = osKernelGetTickCount();
1030     // Calculate the wait time based on wait_period
1031     if ((wait_period & SL_SI91X_WAIT_FOR_EVER) == SL_SI91X_WAIT_FOR_EVER) {
1032       node->command_timeout = osWaitForever;
1033     } else {
1034       node->command_timeout = (wait_period & ~SL_SI91X_WAIT_FOR_RESPONSE_BIT);
1035     }
1036   }
1037   node->sdk_context = NULL;
1038 
1039   CORE_irqState_t state  = CORE_EnterAtomic();
1040   uint8_t this_packet_id = command_packet_id++;
1041   buffer->id             = this_packet_id;
1042   node_buffer->id        = this_packet_id;
1043   sli_si91x_append_to_buffer_queue(&socket->command_queue.tx_queue, node_buffer);
1044   tx_socket_command_queues_status |= (1 << socket->index);
1045   sli_si91x_set_event(SL_SI91X_SOCKET_COMMAND_TX_PENDING_EVENT);
1046   CORE_ExitAtomic(state);
1047 
1048   if (wait_period != 0) {
1049 
1050     uint16_t firmware_status = 0;
1051     sl_si91x_buffer_queue_t *rx_queue;
1052     if (command == RSI_WLAN_REQ_SOCKET_READ_DATA) {
1053       rx_queue = &socket->rx_data_queue;
1054     } else {
1055       rx_queue = &socket->command_queue.rx_queue;
1056     }
1057 
1058     status = sli_si91x_driver_wait_for_response_packet(rx_queue,
1059                                                        si91x_socket_events,
1060                                                        (1 << socket->index),
1061                                                        this_packet_id,
1062                                                        wait_period,
1063                                                        response_buffer);
1064     VERIFY_STATUS_AND_RETURN(status);
1065 
1066     if (command == RSI_WLAN_REQ_SOCKET_READ_DATA) {
1067       sl_si91x_packet_t *packet = (sl_si91x_packet_t *)sl_si91x_host_get_buffer_data(*response_buffer, 0, NULL);
1068       firmware_status           = (uint16_t)(packet->desc[12] + (packet->desc[13] << 8)); // Extract the frame status
1069 
1070     } else {
1071       // Process the response packet and return the firmware status
1072       sli_si91x_queue_packet_t *node =
1073         (sli_si91x_queue_packet_t *)sl_si91x_host_get_buffer_data(*response_buffer, 0, NULL);
1074       firmware_status = node->frame_status;
1075     }
1076     return convert_and_save_firmware_status(firmware_status);
1077   } else {
1078     return SL_STATUS_OK;
1079   }
1080 }
1081 
sli_si91x_send_socket_data(sli_si91x_socket_t * si91x_socket,const sli_si91x_socket_send_request_t * request,const void * data)1082 sl_status_t sli_si91x_send_socket_data(sli_si91x_socket_t *si91x_socket,
1083                                        const sli_si91x_socket_send_request_t *request,
1084                                        const void *data)
1085 {
1086   sl_wifi_buffer_t *buffer;
1087   sl_si91x_packet_t *packet;
1088   sli_si91x_socket_send_request_t *send;
1089 
1090   sl_status_t status     = SL_STATUS_OK;
1091   uint16_t header_length = (request->data_offset - sizeof(sli_si91x_socket_send_request_t));
1092   uint32_t data_length   = request->length;
1093 
1094   if (data == NULL) {
1095     return SL_STATUS_NULL_POINTER;
1096   }
1097 
1098   uint32_t start = osKernelGetTickCount();
1099   while (si91x_socket->data_buffer_limit != 0 && si91x_socket->data_buffer_count >= si91x_socket->data_buffer_limit) {
1100     osDelay(2);
1101     if ((osKernelGetTickCount() - start) > SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME) {
1102       return SL_STATUS_WIFI_BUFFER_ALLOC_FAIL;
1103     }
1104   }
1105 
1106   // Allocate a buffer for the socket data with appropriate size
1107   status = sl_si91x_host_allocate_buffer(
1108     &buffer,
1109     SL_WIFI_TX_FRAME_BUFFER,
1110     sizeof(sl_si91x_packet_t) + sizeof(sli_si91x_socket_send_request_t) + header_length + data_length,
1111     SL_WIFI_ALLOCATE_COMMAND_BUFFER_WAIT_TIME);
1112   VERIFY_STATUS_AND_RETURN(status);
1113 
1114   packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
1115   if (packet == NULL) {
1116     return SL_STATUS_WIFI_BUFFER_ALLOC_FAIL;
1117   }
1118   ++si91x_socket->data_buffer_count;
1119 
1120   memset(packet->desc, 0, sizeof(packet->desc));
1121 
1122   send = (sli_si91x_socket_send_request_t *)packet->data;
1123   memcpy(send, request, sizeof(sli_si91x_socket_send_request_t));
1124   memcpy((send->send_buffer + header_length), data, data_length);
1125 
1126   // Fill frame type
1127   packet->length = (sizeof(sli_si91x_socket_send_request_t) + header_length + data_length) & 0xFFF;
1128 
1129   //  ++data_queue_appended_count;
1130   CORE_irqState_t state = CORE_EnterAtomic();
1131   sli_si91x_append_to_buffer_queue(&si91x_socket->tx_data_queue, buffer);
1132   tx_socket_data_queues_status |= (1 << si91x_socket->index);
1133   sli_si91x_set_event(SL_SI91X_SOCKET_DATA_TX_PENDING_EVENT);
1134   CORE_ExitAtomic(state);
1135 
1136   return SL_STATUS_OK;
1137 }
1138 
sli_si91x_get_socket_id(sl_si91x_packet_t * packet)1139 int sli_si91x_get_socket_id(sl_si91x_packet_t *packet)
1140 {
1141   // Handle connection establishment response
1142   switch (packet->command) {
1143     case RSI_WLAN_RSP_CONN_ESTABLISH:
1144       return ((sl_si91x_rsp_ltcp_est_t *)packet->data)->socket_id;
1145     case RSI_WLAN_RSP_REMOTE_TERMINATE:
1146       return ((sl_si91x_socket_close_response_t *)packet->data)->socket_id;
1147     case RSI_RECEIVE_RAW_DATA:
1148       return *((uint8_t *)&(((sl_si91x_socket_metadata_t *)packet->data)->socket_id));
1149     case RSI_WLAN_RSP_SOCKET_READ_DATA:
1150       return packet->data[0];
1151     case RSI_WLAN_RSP_TCP_ACK_INDICATION:
1152       return ((sl_si91x_rsp_tcp_ack_t *)packet->data)->socket_id;
1153     case RSI_WLAN_RSP_SOCKET_CREATE:
1154       return (((sl_si91x_socket_create_response_t *)packet->data)->socket_id[0]
1155               + (((sl_si91x_socket_create_response_t *)packet->data)->socket_id[1] << 8));
1156     case RSI_WLAN_RSP_SOCKET_CLOSE:
1157       if (((sl_si91x_socket_close_response_t *)packet->data)->socket_id == 0) {
1158         const uint16_t port = ((sl_si91x_socket_close_response_t *)packet->data)->port_number;
1159         for (int i = 0; i < NUMBER_OF_SOCKETS; ++i) {
1160           if (sli_si91x_sockets[i] != NULL && sli_si91x_sockets[i]->local_address.sin6_port == port) {
1161             return sli_si91x_sockets[i]->id;
1162           }
1163         }
1164         return -1;
1165       } else {
1166         return ((sl_si91x_socket_close_response_t *)packet->data)->socket_id;
1167       }
1168     case RSI_WLAN_RSP_SELECT_REQUEST:
1169     default:
1170       return -1;
1171   }
1172 
1173   return -1;
1174 }
1175 
sli_si91x_connect(int socket,const struct sockaddr * addr,socklen_t addr_len)1176 int sli_si91x_connect(int socket, const struct sockaddr *addr, socklen_t addr_len)
1177 {
1178   errno = 0;
1179 
1180   sl_status_t status = SL_STATUS_FAIL;
1181   sli_si91x_socket_t *si91x_socket;
1182 
1183   // Retrieve the socket using the socket index
1184   si91x_socket = get_si91x_socket(socket);
1185 
1186   // Check if the socket is valid.
1187   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
1188 
1189   // Check if the socket is already connected
1190   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type == SOCK_STREAM && si91x_socket->state == CONNECTED, EISCONN);
1191 
1192   // Check the socket state based on its type
1193   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type == SOCK_STREAM && si91x_socket->state > BOUND, EBADF);
1194   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type == SOCK_DGRAM && si91x_socket->state != INITIALIZED
1195                                  && si91x_socket->state != BOUND && si91x_socket->state != UDP_UNCONNECTED_READY,
1196                                EBADF);
1197 
1198   // Check if the provided sockaddr length is sufficient
1199   SET_ERRNO_AND_RETURN_IF_TRUE(
1200     (si91x_socket->local_address.sin6_family == AF_INET && addr_len < sizeof(struct sockaddr_in))
1201       || (si91x_socket->local_address.sin6_family == AF_INET6 && addr_len < sizeof(struct sockaddr_in6)),
1202     EINVAL);
1203 
1204   // Check if the provided sockaddr pointer is valid
1205   SET_ERRNO_AND_RETURN_IF_TRUE(addr == NULL, EFAULT);
1206 
1207   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->local_address.sin6_family != addr->sa_family, EAFNOSUPPORT);
1208 
1209   memcpy(&si91x_socket->remote_address,
1210          addr,
1211          (addr_len > sizeof(struct sockaddr_in6)) ? sizeof(struct sockaddr_in6) : addr_len);
1212 
1213   // Since socket is already created, there is no need to send create request again.
1214   if (si91x_socket->type == SOCK_DGRAM && si91x_socket->state == UDP_UNCONNECTED_READY) {
1215     si91x_socket->state = CONNECTED;
1216 
1217     return SI91X_NO_ERROR;
1218   }
1219 
1220   // Prepare socket request based on socket type and send the request to the bus driver
1221   if (si91x_socket->type == SOCK_STREAM) {
1222     status = create_and_send_socket_request(socket, SI91X_SOCKET_TCP_CLIENT, NULL);
1223   } else if (si91x_socket->type == SOCK_DGRAM) {
1224     status = create_and_send_socket_request(socket, SI91X_SOCKET_UDP_CLIENT, NULL);
1225   }
1226 
1227   // Verify the status of the socket operation and return errors if necessary
1228   SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
1229 
1230   // Update the socket state to "CONNECTED" and return success
1231   si91x_socket->state = CONNECTED;
1232   return SI91X_NO_ERROR;
1233 }
1234 
sli_si91x_bind(int socket_id,const struct sockaddr * addr,socklen_t addr_len)1235 int sli_si91x_bind(int socket_id, const struct sockaddr *addr, socklen_t addr_len)
1236 {
1237   errno = 0;
1238 
1239   // Retrieve the SI91X socket associated with the given socket ID.
1240   sli_si91x_socket_t *si91x_socket         = get_si91x_socket(socket_id);
1241   const struct sockaddr_in *socket_address = (const struct sockaddr_in *)addr;
1242 
1243   // Validate socket, address, and address length
1244   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL || si91x_socket->state != INITIALIZED, EBADF);
1245   SET_ERRNO_AND_RETURN_IF_TRUE(
1246     (si91x_socket->local_address.sin6_family == AF_INET && addr_len < sizeof(struct sockaddr_in))
1247       || (si91x_socket->local_address.sin6_family == AF_INET6 && addr_len < sizeof(struct sockaddr_in6)),
1248     EINVAL);
1249 
1250   SET_ERRNO_AND_RETURN_IF_TRUE(addr == NULL, EFAULT);
1251 
1252   // Check whether local port is already used or not
1253   if (!is_port_available(socket_address->sin_port)) {
1254     SET_ERROR_AND_RETURN(EADDRINUSE);
1255   }
1256 
1257   // Copy the provided address to the local address structure
1258   memcpy(&si91x_socket->local_address,
1259          addr,
1260          (addr_len > sizeof(struct sockaddr_in6)) ? sizeof(struct sockaddr_in6) : addr_len);
1261 
1262   si91x_socket->state = BOUND;
1263 
1264   // For UDP sockets, create and send a socket request.
1265   if (si91x_socket->type == SOCK_DGRAM) {
1266     sl_status_t socket_create_request_status = create_and_send_socket_request(socket_id, SI91X_SOCKET_UDP_CLIENT, NULL);
1267     SOCKET_VERIFY_STATUS_AND_RETURN(socket_create_request_status, SI91X_NO_ERROR, SI91X_UNDEFINED_ERROR);
1268 
1269     si91x_socket->state = UDP_UNCONNECTED_READY;
1270   }
1271 
1272   return SI91X_NO_ERROR;
1273 }
1274 
sli_si91x_select(int nfds,sl_si91x_fd_set * readfds,sl_si91x_fd_set * writefds,sl_si91x_fd_set * exceptfds,const struct timeval * timeout,sl_si91x_socket_select_callback_t callback)1275 int sli_si91x_select(int nfds,
1276                      sl_si91x_fd_set *readfds,
1277                      sl_si91x_fd_set *writefds,
1278                      sl_si91x_fd_set *exceptfds,
1279                      const struct timeval *timeout,
1280                      sl_si91x_socket_select_callback_t callback)
1281 {
1282   UNUSED_PARAMETER(exceptfds);                       // exceptfds is not supported by the firmware, so it is unused
1283   sl_status_t status                 = SL_STATUS_OK; // Initialize status
1284   uint32_t select_response_wait_time = 0;            // Time to wait for the select response
1285 
1286   // Define a structure to hold the select request parameters
1287   sl_si91x_socket_select_req_t request = { 0 };
1288 
1289   // Check if all file descriptor sets are NULL
1290   if ((readfds == NULL) && (writefds == NULL)) {
1291     SET_ERROR_AND_RETURN(EINVAL); // Invalid argument, no sets specified
1292   }
1293 
1294   // Check if the number of file descriptors (nfds) is within a valid range
1295   if (nfds < 0 || nfds > NUMBER_OF_SOCKETS) {
1296     SET_ERROR_AND_RETURN(EINVAL); // Invalid argument, nfds out of range
1297   }
1298 
1299   // Check if the provided timeout is valid
1300   if ((timeout != NULL) && ((timeout->tv_sec < 0) || (timeout->tv_usec < 0))) {
1301     SET_ERROR_AND_RETURN(EINVAL); // Invalid argument, negative timeout
1302   }
1303 
1304   // Loop through the provided file descriptor sets and populate the select request structure
1305   for (uint8_t host_socket_index = 0; host_socket_index < nfds; host_socket_index++) {
1306     const sli_si91x_socket_t *socket =
1307       get_si91x_socket(host_socket_index); // Retrieve the si91x_socket associated with the index
1308 
1309     // Throw error if the socket file descriptor set is invalid
1310     if (socket == NULL
1311         && ((readfds != NULL && SL_SI91X_FD_ISSET(host_socket_index, readfds))
1312             || (writefds != NULL && SL_SI91X_FD_ISSET(host_socket_index, writefds)))) {
1313       SET_ERROR_AND_RETURN(EBADF); // Bad file descriptor
1314     }
1315 
1316     // The code will reach this if clause in the case of a socket being NULL and the socket being neither set in readfds nor writefds.
1317     // Continue to next socket if this one is not in use
1318     if (socket == NULL) {
1319       continue;
1320     }
1321 
1322     // Check if the socket is set for read operations in the readfds set
1323     // Set the corresponding bit in the read file descriptor set
1324     if ((readfds != NULL) && (SL_SI91X_FD_ISSET(host_socket_index, readfds))) {
1325       request.read_fds.fd_array[0] |= (1U << socket->id);
1326     }
1327 
1328     // Check if the socket is set for write operations in the writefds set
1329     // Set the corresponding bit in the write file descriptor set
1330     if ((writefds != NULL) && (SL_SI91X_FD_ISSET(host_socket_index, writefds))) {
1331       request.write_fds.fd_array[0] |= (1U << socket->id);
1332     }
1333 
1334     // Update the maximum file descriptor number encountered
1335     if (request.num_fd <= socket->id) {
1336       request.num_fd = (uint8_t)(socket->id + 1);
1337     }
1338   }
1339 
1340   // Handle timeout: If a timeout is provided, calculate the wait time
1341   if (timeout != NULL) {
1342     request.select_timeout.tv_sec  = timeout->tv_sec;
1343     request.select_timeout.tv_usec = timeout->tv_usec;
1344     // Convert timeout to milliseconds and add extra wait time for the response
1345     select_response_wait_time = ((request.select_timeout.tv_sec * 1000) + (request.select_timeout.tv_usec / 1000)
1346                                  + SI91X_HOST_WAIT_FOR_SELECT_RSP);
1347   } else {
1348     // If no timeout is specified, set the request to indicate no timeout and wait indefinitely
1349     request.no_timeout        = 1;
1350     select_response_wait_time = osWaitForever;
1351   }
1352 
1353   // Get an available select ID from the internal table
1354   sli_si91x_select_request_t *select_request = sli_si91x_get_available_select_id();
1355   // If no select ID is available, return an error
1356   SET_ERRNO_AND_RETURN_IF_TRUE((select_request == NULL), EPERM);
1357   // Assign the callback function for this select request
1358   select_request->select_callback = callback;
1359 
1360   // Set the select_id in the request structure
1361   request.select_id = select_request->select_id;
1362 
1363   // Send the select request asynchronously to the firmware
1364   status = sl_si91x_driver_send_async_command(RSI_WLAN_REQ_SELECT_REQUEST, SI91X_SOCKET_CMD, &request, sizeof(request));
1365   if (status != SL_STATUS_OK) {
1366     // If sending the command fails, clear the select ID and return
1367     sli_si91x_clear_select_id(request.select_id);
1368   }
1369   // Verify that the command was sent successfully
1370   SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
1371 
1372   // If a callback was provided, return immediately (non-blocking)
1373   if (callback != NULL) {
1374     return SL_SI91X_RETURN_IMMEDIATELY;
1375   }
1376 
1377   // Start measuring the time for the select operation
1378   uint32_t start_time   = osKernelGetTickCount();
1379   uint32_t elapsed_time = 0;
1380 
1381   do {
1382     // Wait for the select response event (using the select_id)
1383     uint32_t events = osEventFlagsWait(si91x_socket_select_events,
1384                                        BIT(request.select_id),
1385                                        osFlagsWaitAny,
1386                                        (select_response_wait_time - elapsed_time));
1387 
1388     // Handle cases where the wait times out or resources are unavailable
1389     if (events == (uint32_t)osErrorTimeout || events == (uint32_t)osErrorResource) {
1390       status = SL_STATUS_TIMEOUT; // Set status to timeout if no response was received
1391       break;
1392     } else {
1393       status = SL_STATUS_OK; // Set status to OK if response was received
1394     }
1395 
1396     // Check if the response data for the select request is available
1397     if (select_request_table[request.select_id].response_data != NULL) {
1398       break; // Exit the loop if response is received
1399     }
1400 
1401     // Update the elapsed time
1402     elapsed_time = sl_si91x_host_elapsed_time(start_time);
1403   } while (elapsed_time <= select_response_wait_time);
1404 
1405   // If the select operation timed out or failed, clear the select ID and exit
1406   if (status != SL_STATUS_OK) {
1407     sli_si91x_clear_select_id(request.select_id);
1408   }
1409   // Verify the status and return if an error occurred
1410   SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
1411 
1412   // Convert and save the firmware status from the select request
1413   convert_and_save_firmware_status(select_request_table[request.select_id].frame_status);
1414 
1415   // Initialize the total file descriptor count
1416   int32_t total_fd_set_count = -1;
1417   // If the firmware status is OK, process the select response and update the file descriptor sets
1418   if (select_request_table[request.select_id].frame_status == SL_STATUS_OK) {
1419     total_fd_set_count =
1420       handle_select_response(select_request_table[request.select_id].response_data, readfds, writefds, exceptfds);
1421   }
1422 
1423   // Free the memory allocated for the response data
1424   free(select_request_table[request.select_id].response_data);
1425   // Clear the select ID in the internal table
1426   sli_si91x_clear_select_id(request.select_id);
1427 
1428   // Return the total number of file descriptors set in the read, write, or exception sets
1429   return total_fd_set_count;
1430 }
1431 
sli_si91x_get_available_select_id(void)1432 static sli_si91x_select_request_t *sli_si91x_get_available_select_id(void)
1433 {
1434   // Check if there are any available select request entries.
1435   if (sli_si91x_max_select_count == 0) {
1436     return NULL; // Return NULL if no requests can be processed.
1437   }
1438 
1439   // Enter atomic section to ensure thread-safe access to the select_request_table.
1440   CORE_irqState_t state = CORE_EnterAtomic();
1441 
1442   // Iterate over the select request table to find an available entry.
1443   for (unsigned int i = 0; i < sli_si91x_max_select_count; i++) {
1444     // Check if the current entry is not in use.
1445     if (!select_request_table[i].in_use) {
1446       // Assign the current index as the select ID.
1447       select_request_table[i].select_id = i;
1448 
1449       // Mark the entry as in use.
1450       select_request_table[i].in_use = 1;
1451 
1452       // Exit atomic section after modifying the entry.
1453       CORE_ExitAtomic(state);
1454 
1455       // Return the pointer to the available select request entry.
1456       return &select_request_table[i];
1457     }
1458   }
1459 
1460   // Exit atomic section if no available entry was found.
1461   CORE_ExitAtomic(state);
1462 
1463   // Return NULL to indicate that no available select ID was found.
1464   return NULL;
1465 }
1466 
sli_si91x_clear_select_id(uint8_t id)1467 static void sli_si91x_clear_select_id(uint8_t id)
1468 {
1469   // Check if the select request table is empty or if the provided ID is out of range.
1470   if (sli_si91x_max_select_count == 0 || id >= sli_si91x_max_select_count) {
1471     return; // If no requests or invalid ID, exit early.
1472   }
1473 
1474   // Enter atomic section to ensure thread-safe access to the select_request_table.
1475   CORE_irqState_t state = CORE_EnterAtomic();
1476 
1477   // Mark the entry corresponding to the provided ID as not in use.
1478   select_request_table[id].in_use = 0;
1479 
1480   // Exit atomic section after the operation is complete.
1481   CORE_ExitAtomic(state);
1482 }
1483 
sli_si91x_set_socket_event(uint32_t event_mask)1484 void sli_si91x_set_socket_event(uint32_t event_mask)
1485 {
1486   osEventFlagsSet(si91x_socket_events, event_mask);
1487 }
1488 
sli_si91x_flush_select_request_table(uint16_t error_code)1489 sl_status_t sli_si91x_flush_select_request_table(uint16_t error_code)
1490 {
1491   // Iterate over all entries in the select_request_table
1492   for (unsigned int i = 0; i < sli_si91x_max_select_count; i++) {
1493     // Check if the current select_request_table entry is in use
1494     if (select_request_table[i].in_use) {
1495       // If a callback function exists for this entry, it is async
1496       if (select_request_table[i].select_callback != NULL) {
1497         select_request_table[i].in_use = 0; // Mark as not in use
1498       } else {
1499         // If there is no callback, the request needs to be reset and so the response data pointer is cleared, indicating no data is available
1500         select_request_table[i].response_data = NULL;
1501         // Set the frame status to indicate rejoin failure in the request
1502         select_request_table[i].frame_status = error_code;
1503         // Set the appropriate event flag for the socket associated with the select_id
1504         osEventFlagsSet(si91x_socket_select_events, BIT(select_request_table[i].select_id));
1505       }
1506     }
1507   }
1508   // Return SL_STATUS_OK to indicate the function completed successfully
1509   return SL_STATUS_OK;
1510 }
1511