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