1 /***************************************************************************/ /**
2  * @file  sl_si91x_socket.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_status.h"
32 #include "sl_constants.h"
33 #include "sl_si91x_socket.h"
34 #include "sl_si91x_socket_callback_framework.h"
35 #include "sl_si91x_socket_types.h"
36 #include "sl_si91x_socket_constants.h"
37 #include "sl_si91x_protocol_types.h"
38 #include "sl_rsi_utility.h"
39 #include "sl_si91x_driver.h"
40 #include <stdint.h>
41 #include <string.h>
42 
43 /******************************************************
44  *                      Macros
45  ******************************************************/
46 #define TCP_HEADER_LENGTH          56
47 #define UDP_HEADER_LENGTH          44
48 #define TCP_V6_HEADER_LENGTH       76
49 #define UDP_V6_HEADER_LENGTH       64
50 #define SI91X_SSL_HEADER_SIZE_IPV4 90
51 #define SI91X_SSL_HEADER_SIZE_IPV6 110
52 
sl_si91x_set_remote_termination_callback(sl_si91x_socket_remote_termination_callback_t callback)53 void sl_si91x_set_remote_termination_callback(sl_si91x_socket_remote_termination_callback_t callback)
54 {
55   sli_si91x_set_remote_socket_termination_callback(callback);
56 }
57 
58 // Create a new socket
sl_si91x_socket(int family,int type,int protocol)59 int sl_si91x_socket(int family, int type, int protocol)
60 {
61   return sli_si91x_socket(family, type, protocol, NULL);
62 }
63 
sl_si91x_socket_async(int family,int type,int protocol,sl_si91x_socket_receive_data_callback_t callback)64 int sl_si91x_socket_async(int family, int type, int protocol, sl_si91x_socket_receive_data_callback_t callback)
65 {
66   SET_ERRNO_AND_RETURN_IF_TRUE(NULL == callback, 0);
67 
68   return sli_si91x_socket(family, type, protocol, callback);
69 }
70 
sl_si91x_bind(int socket,const struct sockaddr * addr,socklen_t addr_len)71 int sl_si91x_bind(int socket, const struct sockaddr *addr, socklen_t addr_len)
72 {
73   return sli_si91x_bind(socket, addr, addr_len);
74 }
75 
sl_si91x_connect(int socket,const struct sockaddr * addr,socklen_t addr_len)76 int sl_si91x_connect(int socket, const struct sockaddr *addr, socklen_t addr_len)
77 {
78   return sli_si91x_connect(socket, addr, addr_len);
79 }
80 
sl_si91x_listen(int socket,int max_number_of_clients)81 int sl_si91x_listen(int socket, int max_number_of_clients)
82 {
83   int32_t status;
84   sli_si91x_socket_t *si91x_socket = get_si91x_socket(socket);
85 
86   // Check if the socket is valid
87   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
88   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->state != INITIALIZED && si91x_socket->state != BOUND, EBADF);
89   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type != SOCK_STREAM, EOPNOTSUPP);
90 
91   // Create and send a socket request to make it a TCP server with the specified maximum number of clients
92   status = create_and_send_socket_request(socket, SI91X_SOCKET_TCP_SERVER, &max_number_of_clients);
93   SOCKET_VERIFY_STATUS_AND_RETURN(status, SI91X_NO_ERROR, SI91X_UNDEFINED_ERROR);
94 
95   si91x_socket->state = LISTEN;
96 
97   return SI91X_NO_ERROR;
98 }
99 
sl_si91x_accept(int socket,const struct sockaddr * addr,socklen_t addr_len)100 int sl_si91x_accept(int socket, const struct sockaddr *addr, socklen_t addr_len)
101 {
102   return sli_si91x_accept(socket, (struct sockaddr *)addr, &addr_len, NULL);
103 }
104 
sl_si91x_shutdown(int socket,int how)105 int sl_si91x_shutdown(int socket, int how)
106 {
107   return sli_si91x_shutdown(socket, how);
108 }
109 
sl_si91x_accept_async(int socket,sl_si91x_socket_accept_callback_t callback)110 int sl_si91x_accept_async(int socket, sl_si91x_socket_accept_callback_t callback)
111 {
112   return sli_si91x_accept(socket, NULL, 0, callback);
113 }
114 
sl_si91x_setsockopt(int32_t sockID,int level,int option_name,const void * option_value,socklen_t option_len)115 int sl_si91x_setsockopt(int32_t sockID, int level, int option_name, const void *option_value, socklen_t option_len)
116 {
117   UNUSED_PARAMETER(level);
118 
119   // Retrieve the socket using the socket index
120   sli_si91x_socket_t *si91x_socket = get_si91x_socket(sockID);
121   sl_si91x_time_value *timeout     = NULL;
122   uint16_t timeout_val;
123 
124   // Check if the socket is valid
125   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
126 
127   // Check if the option value is not NULL
128   SET_ERRNO_AND_RETURN_IF_TRUE(option_value == NULL, EFAULT);
129 
130   switch (option_name) {
131     case SL_SI91X_SO_RCVTIME: {
132       // Configure receive timeout
133       timeout = (sl_si91x_time_value *)option_value;
134 
135       // Ensure that the timeout value is at least 1 millisecond
136       if ((timeout->tv_sec == 0) && (timeout->tv_usec != 0) && (timeout->tv_usec < 1000)) {
137         timeout->tv_usec = 1000;
138       }
139       // Calculate the timeout value in milliseconds
140       timeout_val = (uint16_t)((timeout->tv_usec / 1000) + (timeout->tv_sec * 1000));
141 
142       // Need to add check here if Synchronous bit map is set (after async socket_id implementation)
143       memcpy(&si91x_socket->read_timeout,
144              &timeout_val,
145              GET_SAFE_MEMCPY_LENGTH(sizeof(si91x_socket->read_timeout), option_len));
146       break;
147     }
148 
149     case SL_SI91X_SO_MAXRETRY: {
150       // Set the maximum number of TCP retries
151       memcpy(&si91x_socket->max_tcp_retries,
152              (const uint16_t *)option_value,
153              GET_SAFE_MEMCPY_LENGTH(sizeof(si91x_socket->max_tcp_retries), option_len));
154       break;
155     }
156 
157     case SL_SI91X_SO_MSS: {
158       memcpy(&si91x_socket->mss,
159              (const uint16_t *)option_value,
160              GET_SAFE_MEMCPY_LENGTH(sizeof(si91x_socket->mss), option_len));
161       break;
162     }
163 
164     case SL_SI91X_SO_TCP_KEEPALIVE: {
165       // Set the TCP keep-alive initial time
166       memcpy(&si91x_socket->tcp_keepalive_initial_time,
167              (const uint16_t *)option_value,
168              GET_SAFE_MEMCPY_LENGTH(sizeof(si91x_socket->tcp_keepalive_initial_time), option_len));
169       break;
170     }
171     case SL_SI91X_SO_HIGH_PERFORMANCE_SOCKET: {
172       // Enable high-performance socket mode
173       SET_ERRNO_AND_RETURN_IF_TRUE(*(uint8_t *)option_value != SI91X_HIGH_PERFORMANCE_SOCKET, EINVAL);
174       si91x_socket->ssl_bitmap |= SI91X_HIGH_PERFORMANCE_SOCKET;
175       break;
176     }
177 
178     case SL_SI91X_SO_SSL_ENABLE: {
179       // Enable SSL for the socket
180       SET_ERRNO_AND_RETURN_IF_TRUE((*(uint8_t *)option_value) != SI91X_SOCKET_FEAT_SSL, EINVAL);
181       si91x_socket->ssl_bitmap |= SI91X_SOCKET_FEAT_SSL;
182       break;
183     }
184     case SL_SI91X_SO_SSL_V_1_0_ENABLE: {
185       // Enable SSL version 1.0 for the socket
186       SET_ERRNO_AND_RETURN_IF_TRUE(((*(uint8_t *)option_value) != (SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_0)),
187                                    EINVAL);
188       si91x_socket->ssl_bitmap |= SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_0;
189       break;
190     }
191     case SL_SI91X_SO_SSL_V_1_1_ENABLE: {
192       // Enable SSL version 1.1 for the socket
193       SET_ERRNO_AND_RETURN_IF_TRUE(((*(uint8_t *)option_value) != (SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_1)),
194                                    EINVAL);
195       si91x_socket->ssl_bitmap |= SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_1;
196       break;
197     }
198     case SL_SI91X_SO_SSL_V_1_2_ENABLE: {
199       // Enable SSL version 1.2 for the socket
200       SET_ERRNO_AND_RETURN_IF_TRUE(((*(uint8_t *)option_value) != (SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_2)),
201                                    EINVAL);
202       si91x_socket->ssl_bitmap |= SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_2;
203       break;
204     }
205 
206     case SL_SI91X_SO_SOCK_VAP_ID: {
207       // Set the VAP ID for the socket
208       si91x_socket->vap_id = *((const uint8_t *)option_value);
209       break;
210     }
211 
212     case SL_SI91x_SO_TCP_ACK_INDICATION: {
213       // Enable TCP_ACK_INDICATION
214       SET_ERRNO_AND_RETURN_IF_TRUE((*(uint8_t *)option_value) != SI91X_SOCKET_FEAT_TCP_ACK_INDICATION, EINVAL);
215       si91x_socket->socket_bitmap |= SI91X_SOCKET_FEAT_TCP_ACK_INDICATION;
216       break;
217     }
218 #if defined(SLI_SI917) || defined(SLI_SI915)
219     case SL_SI91X_SO_SSL_V_1_3_ENABLE: {
220       // Enable SSL version 1.3 for the socket.
221       SET_ERRNO_AND_RETURN_IF_TRUE(((*(uint8_t *)option_value) != (SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_3)),
222                                    EINVAL);
223       si91x_socket->ssl_bitmap |= SI91X_SOCKET_FEAT_SSL | SL_SI91X_TLS_V_1_3;
224       break;
225     }
226 #endif
227 
228     case SL_SI91X_SO_CERT_INDEX: {
229       SET_ERRNO_AND_RETURN_IF_TRUE(
230         ((*(uint8_t *)option_value < SI91X_CERT_INDEX_0) || (*(uint8_t *)option_value > SI91X_CERT_INDEX_2)),
231         EINVAL);
232 
233       si91x_socket->certificate_index = *(const uint8_t *)option_value;
234       break;
235     }
236 
237     case SL_SI91X_SO_TLS_SNI:
238     case SL_SI91X_SO_TLS_ALPN: {
239       sl_status_t status = sli_si91x_add_tls_extension(&si91x_socket->tls_extensions,
240                                                        (const sl_si91x_socket_type_length_value_t *)option_value);
241 
242       if (status != SL_STATUS_OK) {
243         SET_ERROR_AND_RETURN(ENOMEM);
244       }
245       break;
246     }
247 
248 #if defined(SLI_SI917) || defined(SLI_SI915)
249     case SL_SI91X_SO_MAX_RETRANSMISSION_TIMEOUT_VALUE: {
250       if (IS_POWER_OF_TWO((*(uint8_t *)option_value))
251           && ((*(const uint8_t *)option_value) < MAX_RETRANSMISSION_TIME_VALUE)) {
252         memcpy(&si91x_socket->max_retransmission_timeout_value,
253                (const uint8_t *)option_value,
254                GET_SAFE_MEMCPY_LENGTH(sizeof(si91x_socket->max_retransmission_timeout_value), option_len));
255       } else {
256         SL_DEBUG_LOG("\n Max retransmission timeout value in between 1 - 32 and "
257                      "should be power of two. ex:1,2,4,8,16,32 \n");
258         SET_ERROR_AND_RETURN(EINVAL);
259       }
260       break;
261     }
262 #endif
263     default: {
264       // Invalid socket option
265       SET_ERROR_AND_RETURN(ENOPROTOOPT);
266     }
267   }
268   return SI91X_NO_ERROR;
269 }
270 
sl_si91x_send(int socket,const uint8_t * buffer,size_t buffer_length,int32_t flags)271 int sl_si91x_send(int socket, const uint8_t *buffer, size_t buffer_length, int32_t flags)
272 {
273   return sl_si91x_send_async(socket, buffer, buffer_length, flags, NULL);
274 }
275 
sl_si91x_send_async(int socket,const uint8_t * buffer,size_t buffer_length,int32_t flags,sl_si91x_socket_data_transfer_complete_handler_t callback)276 int sl_si91x_send_async(int socket,
277                         const uint8_t *buffer,
278                         size_t buffer_length,
279                         int32_t flags,
280                         sl_si91x_socket_data_transfer_complete_handler_t callback)
281 {
282   return sl_si91x_sendto_async(socket, buffer, buffer_length, flags, NULL, 0, callback);
283 }
284 
sl_si91x_sendto(int socket,const uint8_t * buffer,size_t buffer_length,int32_t flags,const struct sockaddr * addr,socklen_t addr_len)285 int sl_si91x_sendto(int socket,
286                     const uint8_t *buffer,
287                     size_t buffer_length,
288                     int32_t flags,
289                     const struct sockaddr *addr,
290                     socklen_t addr_len)
291 {
292   return sl_si91x_sendto_async(socket, buffer, buffer_length, flags, addr, addr_len, NULL);
293 }
294 
sl_si91x_send_large_data(int socket,const uint8_t * buffer,size_t buffer_length,int32_t flags)295 int sl_si91x_send_large_data(int socket, const uint8_t *buffer, size_t buffer_length, int32_t flags)
296 {
297   const sli_si91x_socket_t *si91x_socket = get_si91x_socket(socket);
298   int bsd_ret_code                       = 0;
299   size_t offset                          = 0;
300   size_t chunk_size                      = 0;
301   size_t max_len                         = 0;
302 
303   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
304   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->state == RESET || si91x_socket->state == INITIALIZED, EBADF);
305   SET_ERRNO_AND_RETURN_IF_TRUE(buffer == NULL, EFAULT);
306 
307   // Find maximum limit based on the protocol
308   if (si91x_socket->type == SOCK_STREAM && si91x_socket->ssl_bitmap & SL_SI91X_ENABLE_TLS) {
309     max_len = (si91x_socket->local_address.sin6_family == AF_INET) ? si91x_socket->mss - SI91X_SSL_HEADER_SIZE_IPV4
310                                                                    : si91x_socket->mss - SI91X_SSL_HEADER_SIZE_IPV6;
311   } else if (si91x_socket->type == SOCK_DGRAM) {
312     max_len = (si91x_socket->local_address.sin6_family == AF_INET) ? DEFAULT_DATAGRAM_MSS_SIZE_IPV4
313                                                                    : DEFAULT_DATAGRAM_MSS_SIZE_IPV6;
314   } else {
315     max_len = (si91x_socket->local_address.sin6_family == AF_INET) ? DEFAULT_STREAM_MSS_SIZE_IPV4
316                                                                    : DEFAULT_STREAM_MSS_SIZE_IPV6;
317   }
318 
319   while (offset < buffer_length) {
320     chunk_size = (max_len < (buffer_length - offset)) ? max_len : (buffer_length - offset);
321     // Send chunk of data and return the total data sent in successful case
322     bsd_ret_code = sl_si91x_send_async(socket, buffer + offset, chunk_size, flags, NULL);
323     if (bsd_ret_code < 0) {
324       SL_DEBUG_LOG("\n Send failed with error code 0x%X \n", errno);
325       break;
326     } else {
327       offset += bsd_ret_code;
328     }
329   }
330   return offset;
331 }
332 
sl_si91x_sendto_async(int socket,const uint8_t * buffer,size_t buffer_length,int32_t flags,const struct sockaddr * to_addr,socklen_t to_addr_len,sl_si91x_socket_data_transfer_complete_handler_t callback)333 int sl_si91x_sendto_async(int socket,
334                           const uint8_t *buffer,
335                           size_t buffer_length,
336                           int32_t flags,
337                           const struct sockaddr *to_addr,
338                           socklen_t to_addr_len,
339                           sl_si91x_socket_data_transfer_complete_handler_t callback)
340 {
341 
342   UNUSED_PARAMETER(flags);
343   sl_status_t status                      = SL_STATUS_OK;
344   sli_si91x_socket_t *si91x_socket        = get_si91x_socket(socket);
345   sli_si91x_socket_send_request_t request = { 0 };
346 
347   // Check if the socket is valid
348   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
349   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type == SOCK_STREAM && si91x_socket->state != CONNECTED, ENOTCONN);
350   SET_ERRNO_AND_RETURN_IF_TRUE(buffer == NULL, EFAULT);
351   if (si91x_socket->socket_bitmap & SI91X_SOCKET_FEAT_TCP_ACK_INDICATION) {
352     SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->is_waiting_on_ack == true, EWOULDBLOCK);
353   }
354   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->state != CONNECTED && to_addr == NULL, EFAULT);
355 
356   // Set the data transfer callback for this socket
357   si91x_socket->data_transfer_callback = callback;
358 
359   // Check message size depending on socket type
360   if (si91x_socket->type == SOCK_STREAM) {
361     if (si91x_socket->ssl_bitmap & SL_SI91X_ENABLE_TLS) {
362       // For SOCK_STREAM (TCP), consider SSL overhead if TLS is enabled
363       size_t max_size = (si91x_socket->local_address.sin6_family == AF_INET)
364                           ? si91x_socket->mss - SI91X_SSL_HEADER_SIZE_IPV4
365                           : si91x_socket->mss - SI91X_SSL_HEADER_SIZE_IPV6;
366       SET_ERRNO_AND_RETURN_IF_TRUE(buffer_length > max_size, EMSGSIZE);
367     } else {
368       size_t max_size = (si91x_socket->local_address.sin6_family == AF_INET) ? DEFAULT_STREAM_MSS_SIZE_IPV4
369                                                                              : DEFAULT_STREAM_MSS_SIZE_IPV6;
370       SET_ERRNO_AND_RETURN_IF_TRUE(buffer_length > max_size, EMSGSIZE);
371     }
372     if (si91x_socket->socket_bitmap & SI91X_SOCKET_FEAT_TCP_ACK_INDICATION) {
373       // When using SOCK_STREAM (TCP), socket will wait for an ack if the SI91X_SOCKET_FEAT_TCP_ACK_INDICATION bit is set.
374       si91x_socket->is_waiting_on_ack = true;
375     }
376   } else if (si91x_socket->type == SOCK_DGRAM) {
377     // For SOCK_DGRAM (UDP), check the message size against the default maximum size
378     size_t max_size = (si91x_socket->local_address.sin6_family == AF_INET) ? DEFAULT_DATAGRAM_MSS_SIZE_IPV4
379                                                                            : DEFAULT_DATAGRAM_MSS_SIZE_IPV6;
380     SET_ERRNO_AND_RETURN_IF_TRUE(buffer_length > max_size, EMSGSIZE);
381   }
382 
383   if (si91x_socket->type == SOCK_DGRAM && (si91x_socket->state == BOUND || si91x_socket->state == INITIALIZED)) {
384     status = create_and_send_socket_request(socket, SI91X_SOCKET_UDP_CLIENT, NULL);
385 
386     SET_ERRNO_AND_RETURN_IF_TRUE(status != SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
387     si91x_socket->state = UDP_UNCONNECTED_READY;
388   }
389 
390   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type == SOCK_DGRAM && si91x_socket->state != CONNECTED
391                                  && si91x_socket->state != UDP_UNCONNECTED_READY,
392                                EBADF);
393 
394   SET_ERRNO_AND_RETURN_IF_TRUE(
395     si91x_socket->state == UDP_UNCONNECTED_READY
396       && ((si91x_socket->local_address.sin6_family == AF_INET && to_addr_len < sizeof(struct sockaddr_in))
397           || (si91x_socket->local_address.sin6_family == AF_INET6 && to_addr_len < sizeof(struct sockaddr_in6))),
398     EINVAL);
399 
400   // create a socket send request
401   if (si91x_socket->local_address.sin6_family == AF_INET6) {
402     // If the socket uses IPv6, set the IP version and destination IPv6 address
403     const struct sockaddr_in6 *socket_address = (const struct sockaddr_in6 *)to_addr;
404     request.ip_version                        = SL_IPV6_ADDRESS_LENGTH;
405     request.data_offset = (si91x_socket->type == SOCK_STREAM) ? TCP_V6_HEADER_LENGTH : UDP_V6_HEADER_LENGTH;
406     const uint8_t *destination_ip =
407       (si91x_socket->state == UDP_UNCONNECTED_READY || to_addr_len >= sizeof(struct sockaddr_in6))
408         ? socket_address->sin6_addr.s6_addr
409         : si91x_socket->remote_address.sin6_addr.s6_addr;
410 
411     memcpy(&request.dest_ip_addr.ipv6_address[0], destination_ip, SL_IPV6_ADDRESS_LENGTH);
412   } else {
413     // If the socket uses IPv4, set the IP version and destination IPv4 address
414     const struct sockaddr_in *socket_address = (const struct sockaddr_in *)to_addr;
415     request.ip_version                       = SL_IPV4_ADDRESS_LENGTH;
416     request.data_offset = (si91x_socket->type == SOCK_STREAM) ? TCP_HEADER_LENGTH : UDP_HEADER_LENGTH;
417     uint32_t destination_ip =
418       (si91x_socket->state == UDP_UNCONNECTED_READY || to_addr_len >= sizeof(struct sockaddr_in))
419         ? socket_address->sin_addr.s_addr
420         : ((struct sockaddr_in *)&si91x_socket->remote_address)->sin_addr.s_addr;
421 
422     memcpy(&request.dest_ip_addr.ipv4_address[0], &destination_ip, SL_IPV4_ADDRESS_LENGTH);
423   }
424   // Set other parameters in the send request
425   request.socket_id = (uint16_t)si91x_socket->id;
426   request.dest_port = (si91x_socket->state == UDP_UNCONNECTED_READY || to_addr_len > 0)
427                         ? ((const struct sockaddr_in *)to_addr)->sin_port
428                         : si91x_socket->remote_address.sin6_port;
429   request.length    = buffer_length;
430 
431   // Send the socket data
432   status = sl_si91x_driver_send_socket_data(&request, buffer, 0);
433   if (status != SL_STATUS_OK && (si91x_socket->socket_bitmap & SI91X_SOCKET_FEAT_TCP_ACK_INDICATION)) {
434     si91x_socket->is_waiting_on_ack = false;
435   }
436   SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, ENOBUFS);
437 
438   return buffer_length;
439 }
440 
sl_si91x_recv(int socket,uint8_t * buf,size_t buf_len,int32_t flags)441 int sl_si91x_recv(int socket, uint8_t *buf, size_t buf_len, int32_t flags)
442 {
443   return sl_si91x_recvfrom(socket, buf, buf_len, flags, NULL, NULL);
444 }
445 
sl_si91x_recvfrom(int socket,uint8_t * buf,size_t buf_len,int32_t flags,struct sockaddr * addr,socklen_t * addr_len)446 int sl_si91x_recvfrom(int socket,
447                       uint8_t *buf,
448                       size_t buf_len,
449                       int32_t flags,
450                       struct sockaddr *addr,
451                       socklen_t *addr_len)
452 {
453   UNUSED_PARAMETER(flags);
454 
455   // Initialize variables for socket communication
456   sl_si91x_wait_period_t wait_time     = 0;
457   sl_si91x_req_socket_read_t request   = { 0 };
458   ssize_t bytes_read                   = 0;
459   size_t max_buf_len                   = 0;
460   sl_si91x_socket_metadata_t *response = NULL;
461   sli_si91x_socket_t *si91x_socket     = get_si91x_socket(socket);
462   sl_wifi_buffer_t *buffer             = NULL;
463   sl_si91x_packet_t *packet            = NULL;
464 
465   // Check if the socket is valid
466   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket == NULL, EBADF);
467   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->type == SOCK_STREAM && si91x_socket->state != CONNECTED, ENOTCONN);
468 
469   // Check if the buffer pointer is valid
470   SET_ERRNO_AND_RETURN_IF_TRUE(buf == NULL, EFAULT);
471 
472   // Check if the specified buffer length is valid
473   SET_ERRNO_AND_RETURN_IF_TRUE(buf_len <= 0, EINVAL);
474 
475   // create and send a socket request to configure it as UDP.
476   if (si91x_socket->type == SOCK_DGRAM && (si91x_socket->state == BOUND || si91x_socket->state == INITIALIZED)) {
477     int bsd_status = create_and_send_socket_request(socket, SI91X_SOCKET_UDP_CLIENT, NULL);
478     SOCKET_VERIFY_STATUS_AND_RETURN(bsd_status, SI91X_NO_ERROR, SI91X_UNDEFINED_ERROR);
479 
480     si91x_socket->state = UDP_UNCONNECTED_READY;
481   }
482 
483   // Possible states are only reset and disconnected.
484   SET_ERRNO_AND_RETURN_IF_TRUE(si91x_socket->state != CONNECTED && si91x_socket->state != UDP_UNCONNECTED_READY, EBADF);
485 
486   // Limit the buffer length based on the socket type
487   if (si91x_socket->local_address.sin6_family == AF_INET) {
488     if (si91x_socket->type == SOCK_STREAM) {
489       max_buf_len = DEFAULT_STREAM_MSS_SIZE_IPV4;
490     } else if (si91x_socket->type == SOCK_DGRAM) {
491       max_buf_len = DEFAULT_DATAGRAM_MSS_SIZE_IPV4;
492     }
493   } else if (si91x_socket->local_address.sin6_family == AF_INET6) {
494     if (si91x_socket->type == SOCK_STREAM) {
495       max_buf_len = DEFAULT_STREAM_MSS_SIZE_IPV6;
496     } else if (si91x_socket->type == SOCK_DGRAM) {
497       max_buf_len = DEFAULT_DATAGRAM_MSS_SIZE_IPV6;
498     }
499   }
500 
501   if (max_buf_len && (buf_len > max_buf_len)) {
502     buf_len = max_buf_len;
503   }
504   // Initialize the socket read request with the socket ID and requested buffer length
505   request.socket_id = (uint8_t)si91x_socket->id;
506   memcpy(request.requested_bytes, &buf_len, sizeof(buf_len));
507   memcpy(request.read_timeout, &si91x_socket->read_timeout, sizeof(si91x_socket->read_timeout));
508   wait_time = (SL_SI91X_WAIT_FOR_EVER | SL_SI91X_WAIT_FOR_RESPONSE_BIT);
509 
510   sl_status_t status = sli_si91x_send_socket_command(si91x_socket,
511                                                      RSI_WLAN_REQ_SOCKET_READ_DATA,
512                                                      &request,
513                                                      sizeof(request),
514                                                      wait_time,
515                                                      &buffer);
516 
517   // If the command failed and a buffer was allocated, free the buffer
518   if ((status != SL_STATUS_OK) && (buffer != NULL)) {
519     sl_si91x_host_free_buffer(buffer);
520   }
521 
522   SOCKET_VERIFY_STATUS_AND_RETURN(status, SL_STATUS_OK, SI91X_UNDEFINED_ERROR);
523 
524   // Retrieve the packet from the buffer
525   packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
526 
527   // Extract the socket receive response data from the firmware packet
528   response = (sl_si91x_socket_metadata_t *)packet->data;
529 
530   // Determine the number of bytes read, considering the buffer length and response length
531   bytes_read = (response->length <= buf_len) ? response->length : buf_len;
532   memcpy(buf, ((uint8_t *)response + response->offset), bytes_read);
533 
534   // If address information is provided, populate it based on the IP version
535   if (addr != NULL) {
536     if (response->ip_version == SL_IPV4_ADDRESS_LENGTH && *addr_len >= sizeof(struct sockaddr_in)) {
537       struct sockaddr_in *socket_address = (struct sockaddr_in *)addr;
538 
539       socket_address->sin_port   = response->dest_port;
540       socket_address->sin_family = AF_INET;
541       memcpy(&socket_address->sin_addr.s_addr, response->dest_ip_addr.ipv4_address, SL_IPV4_ADDRESS_LENGTH);
542 
543       *addr_len = sizeof(struct sockaddr_in);
544     } else if (response->ip_version == SL_IPV6_ADDRESS_LENGTH && *addr_len >= sizeof(struct sockaddr_in6)) {
545       struct sockaddr_in6 *ipv6_socket_address = ((struct sockaddr_in6 *)addr);
546 
547       ipv6_socket_address->sin6_port   = response->dest_port;
548       ipv6_socket_address->sin6_family = AF_INET;
549       memcpy(&ipv6_socket_address->sin6_addr.s6_addr,
550              response->dest_ip_addr.ipv6_address,
551              SL_IPV6_ADDRESS_LENGTH);
552 
553       *addr_len = sizeof(struct sockaddr_in6);
554     } else {
555       *addr_len = 0;
556     }
557   }
558 
559   sl_si91x_host_free_buffer(buffer);
560 
561   return bytes_read;
562 }
563 
sl_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)564 int sl_si91x_select(int nfds,
565                     sl_si91x_fd_set *readfds,
566                     sl_si91x_fd_set *writefds,
567                     sl_si91x_fd_set *exceptfds,
568                     const struct timeval *timeout,
569                     sl_si91x_socket_select_callback_t callback)
570 {
571   return sli_si91x_select(nfds, readfds, writefds, exceptfds, timeout, callback);
572 }
573