1 /***************************************************************************/ /**
2  * @file
3  * @brief
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 #include "sl_status.h"
31 #include "sl_utility.h"
32 #include "sl_net.h"
33 #include "sl_wifi.h"
34 #include "sl_net_wifi_types.h"
35 #include "sl_net_si91x.h"
36 #include "sl_si91x_host_interface.h"
37 #include "sl_si91x_driver.h"
38 #include "sl_rsi_utility.h"
39 #include "sl_net_rsi_utility.h"
40 #include "sl_si91x_core_utilities.h"
41 #include <stdbool.h>
42 #include <string.h>
43 
44 // Define a bit mask for DHCP unicast offer
45 #define SL_SI91X_DHCP_UNICAST_OFFER ((uint32_t)1U << 3)
46 
47 // Global variable indicating if the device is initialized
48 extern bool device_initialized;
49 
sli_si91x_configure_ip_address(sl_net_ip_configuration_t * ip_config,uint8_t virtual_ap_id,const uint32_t timeout)50 sl_status_t sli_si91x_configure_ip_address(sl_net_ip_configuration_t *ip_config,
51                                            uint8_t virtual_ap_id,
52                                            const uint32_t timeout)
53 {
54   sl_status_t status                      = SL_STATUS_INVALID_PARAMETER;
55   sl_si91x_req_ipv4_params_t ip_req       = { 0 };
56   sl_si91x_req_ipv6_params_t ipv6_request = { 0 };
57   sl_si91x_packet_t *packet;
58   sl_wifi_buffer_t *buffer = NULL;
59   uint32_t wait_time       = (timeout ? SL_SI91X_WAIT_FOR_RESPONSE(timeout) : SL_SI91X_RETURN_IMMEDIATELY);
60 
61   // Check if the device is initialized
62   if (!device_initialized) {
63     return SL_STATUS_NOT_INITIALIZED;
64   }
65 
66   // Check for NULL ip_config pointer
67   if (NULL == ip_config) {
68     return SL_STATUS_INVALID_PARAMETER;
69   }
70 
71   // Check if timeout is 0
72   if (0 == timeout) {
73     return SL_STATUS_INVALID_PARAMETER;
74   }
75 
76   if (SL_IPV4 & ip_config->type) {
77     // Initialize the IPv4 request structure and fill fields accordingly
78     memset(&ip_req, 0, sizeof(ip_req));
79     ip_req.vap_id = virtual_ap_id;
80 
81     if (SL_IP_MANAGEMENT_STATIC_IP == ip_config->mode) {
82       ip_req.dhcp_mode = SL_SI91X_STATIC;
83       // Fill IP address
84       memcpy(ip_req.ipaddress, ip_config->ip.v4.ip_address.bytes, 4);
85 
86       // Fill network mask
87       memcpy(ip_req.netmask, ip_config->ip.v4.netmask.bytes, 4);
88 
89       // Fill gateway
90       memcpy(ip_req.gateway, ip_config->ip.v4.gateway.bytes, 4);
91     } else {
92       ip_req.dhcp_mode = (SL_SI91X_DHCP | SL_SI91X_DHCP_UNICAST_OFFER);
93     }
94 
95     if (NULL != ip_config->host_name) {
96       // Enable DHCP hostname option and copy the hostname
97       ip_req.dhcp_mode |= SL_SI91X_DHCP_HOSTNAME;
98       memcpy(ip_req.hostname, ip_config->host_name, sizeof(ip_req.hostname));
99     }
100 
101     ip_req.dhcp_discover_rtr_interval_min = ip_config->dhcp_config.min_discover_retry_interval;
102     ip_req.dhcp_request_rtr_interval_min  = ip_config->dhcp_config.min_request_retry_interval;
103     ip_req.dhcp_discover_rtr_interval_max = ip_config->dhcp_config.max_discover_retry_interval;
104     ip_req.dhcp_request_rtr_interval_max  = ip_config->dhcp_config.max_request_retry_interval;
105     ip_req.dhcp_discover_max_retries      = ip_config->dhcp_config.min_discover_retries;
106     ip_req.dhcp_request_max_retries       = ip_config->dhcp_config.max_request_retries;
107 
108     status = sl_si91x_driver_send_command(RSI_WLAN_REQ_IPCONFV4,
109                                           SI91X_NETWORK_CMD,
110                                           &ip_req,
111                                           sizeof(sl_si91x_req_ipv4_params_t),
112                                           wait_time,
113                                           NULL,
114                                           &buffer);
115 
116     // Check if the command failed and free the buffer if it was allocated
117     if ((status != SL_STATUS_OK) && (buffer != NULL)) {
118       sl_si91x_host_free_buffer(buffer);
119     }
120 
121     // Verify the status and return it
122     VERIFY_STATUS_AND_RETURN(status);
123     packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
124 
125     if (SL_IP_MANAGEMENT_DHCP == ip_config->mode) {
126       // Extract DHCP response data if in DHCP mode
127       const sl_si91x_rsp_ipv4_params_t *response_data = (sl_si91x_rsp_ipv4_params_t *)packet->data;
128       memcpy(ip_config->ip.v4.ip_address.bytes, (const uint8_t *)response_data->ipaddr, sizeof(sl_ipv4_address_t));
129       memcpy(ip_config->ip.v4.netmask.bytes, (const uint8_t *)response_data->netmask, sizeof(sl_ipv4_address_t));
130       memcpy(ip_config->ip.v4.gateway.bytes, (const uint8_t *)response_data->gateway, sizeof(sl_ipv4_address_t));
131     }
132 
133     // Free the buffer and return success status
134     sl_si91x_host_free_buffer(buffer);
135   }
136 
137   if (SL_IPV6 & ip_config->type) {
138     // Initialize the IPv6 request structure
139     memset(&ipv6_request, 0, sizeof(ipv6_request));
140     uint16_t prefix_length = 64;
141     memcpy(&ipv6_request.prefixLength, &prefix_length, 2);
142     ipv6_request.vap_id = virtual_ap_id;
143 
144     if (SL_IP_MANAGEMENT_STATIC_IP == ip_config->mode) {
145       // Set IPv6 mode to static
146       memcpy(&ipv6_request.ipaddr6, ip_config->ip.v6.global_address.bytes, SL_IPV6_ADDRESS_LENGTH);
147       memcpy(&ipv6_request.gateway6, ip_config->ip.v6.gateway.bytes, SL_IPV6_ADDRESS_LENGTH);
148       ipv6_request.mode[0] = SL_SI91X_STATIC;
149     } else {
150       // Set IPv6 mode to dynamic
151       ipv6_request.mode[0] = (SL_SI91X_DHCP | SL_SI91X_DHCP_UNICAST_OFFER);
152     }
153 
154     // Send the IPv6 configuration request to SI91X driver
155     status = sl_si91x_driver_send_command(RSI_WLAN_REQ_IPCONFV6,
156                                           SI91X_NETWORK_CMD,
157                                           &ipv6_request,
158                                           sizeof(sl_si91x_req_ipv6_params_t),
159                                           wait_time,
160                                           NULL,
161                                           &buffer);
162 
163     // Check if the command failed and free the buffer if it was allocated
164     if ((status != SL_STATUS_OK) && (buffer != NULL)) {
165       sl_si91x_host_free_buffer(buffer);
166     }
167 
168     VERIFY_STATUS_AND_RETURN(status);
169 
170     // Extract the IPv6 configuration response data
171     packet                                          = sl_si91x_host_get_buffer_data(buffer, 0, NULL);
172     const sl_si91x_rsp_ipv6_params_t *ipv6_response = (sl_si91x_rsp_ipv6_params_t *)packet->data;
173 
174     // Copy the IPv6 addresses to the address structure
175     memcpy(&ip_config->ip.v6.link_local_address,
176            (const uint8_t *)ipv6_response->link_local_address,
177            sizeof(ipv6_response->link_local_address));
178     memcpy(&ip_config->ip.v6.global_address,
179            (const uint8_t *)ipv6_response->global_address,
180            sizeof(ipv6_response->global_address));
181     memcpy(&ip_config->ip.v6.gateway,
182            (const uint8_t *)ipv6_response->gateway_address,
183            sizeof(ipv6_response->gateway_address));
184 
185     // Free the buffer and return success status
186     sl_si91x_host_free_buffer(buffer);
187   }
188 
189   return status;
190 }
191 
sl_si91x_ota_firmware_upgradation(sl_ip_address_t server_ip,uint16_t server_port,uint16_t chunk_number,uint16_t timeout,uint16_t tcp_retry_count,bool asynchronous)192 sl_status_t sl_si91x_ota_firmware_upgradation(sl_ip_address_t server_ip,
193                                               uint16_t server_port,
194                                               uint16_t chunk_number,
195                                               uint16_t timeout,
196                                               uint16_t tcp_retry_count,
197                                               bool asynchronous)
198 {
199   sl_wifi_buffer_t *buffer           = NULL;
200   sl_status_t status                 = SL_STATUS_FAIL;
201   sl_si91x_wait_period_t wait_period = SL_SI91X_RETURN_IMMEDIATELY;
202 
203   // Initialize the OTA firmware update request structure
204   sl_si91x_ota_firmware_update_request_t otaf_fwup = { 0 };
205 
206   // Determine the wait period based on the 'asynchronous' flag
207   if (asynchronous == false) {
208     wait_period = SL_SI91X_WAIT_FOR_OTAF_RESPONSE;
209   }
210 
211   // Check IP version
212   if (server_ip.type == SL_IPV4) {
213     // Fill the IP version
214     otaf_fwup.ip_version = SL_IPV4;
215     memcpy(otaf_fwup.server_ip_address.ipv4_address, server_ip.ip.v4.bytes, SL_IPV4_ADDRESS_LENGTH);
216   } else if (server_ip.type == SL_IPV6) {
217     otaf_fwup.ip_version = SL_IPV6;
218     memcpy(otaf_fwup.server_ip_address.ipv6_address, server_ip.ip.v6.bytes, SL_IPV6_ADDRESS_LENGTH);
219   } else {
220     return SL_STATUS_INVALID_PARAMETER;
221   }
222 
223   // Fill server port number
224   memcpy(otaf_fwup.server_port, &server_port, sizeof(server_port));
225 
226   // Fill chunk number
227   memcpy(otaf_fwup.chunk_number, &chunk_number, sizeof(otaf_fwup.chunk_number));
228 
229   // Fill timeout
230   memcpy(otaf_fwup.timeout, &timeout, sizeof(otaf_fwup.timeout));
231 
232   // Fill TCP retry count
233   memcpy(otaf_fwup.retry_count, &tcp_retry_count, sizeof(otaf_fwup.retry_count));
234 
235   status = sl_si91x_driver_send_command(RSI_WLAN_REQ_OTA_FWUP,
236                                         SI91X_NETWORK_CMD,
237                                         &otaf_fwup,
238                                         sizeof(sl_si91x_ota_firmware_update_request_t),
239                                         wait_period,
240                                         NULL,
241                                         &buffer);
242 
243   // Check if the command was synchronous and free the buffer if it was allocated
244   if (asynchronous == false) {
245     if (status != SL_STATUS_OK && buffer != NULL) {
246       sl_si91x_host_free_buffer(buffer);
247     }
248     VERIFY_STATUS_AND_RETURN(status);
249   }
250   sl_si91x_host_free_buffer(buffer);
251   return status;
252 }
253 
sl_si91x_configure_ip_address(sl_net_ip_configuration_t * address,uint8_t virtual_ap_id)254 sl_status_t sl_si91x_configure_ip_address(sl_net_ip_configuration_t *address, uint8_t virtual_ap_id)
255 {
256   return sli_si91x_configure_ip_address(address, virtual_ap_id, 150000);
257 }