/***************************************************************************/ /** * @file * @brief ******************************************************************************* * # License * Copyright 2019 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #include "sl_status.h" #include "sl_wifi_types.h" #include "sl_net.h" #include "stddef.h" #include "sl_status.h" #include "sl_utility.h" #include "sl_net.h" #include "sl_wifi.h" #include "sl_net_wifi_types.h" #include "sl_net_si91x.h" #include "sl_si91x_host_interface.h" #include "sl_si91x_driver.h" #include "sl_rsi_utility.h" #include "sl_net_rsi_utility.h" #include "sl_si91x_core_utilities.h" #include #include #include "sl_wifi_callback_framework.h" #include "sl_net_dns.h" typedef enum { SLI_SI91X_CLIENT = 0, SLI_SI91X_AP = 1, SLI_SI91X_MAX_INTERFACES } sli_si91x_interfaces_t; static sl_status_t sli_si91x_send_multicast_request(sl_wifi_interface_t interface, const sl_ip_address_t *ip_address, uint8_t command_type); sl_status_t sl_net_dns_resolve_hostname(const char *host_name, const uint32_t timeout, const sl_net_dns_resolution_ip_type_t dns_resolution_ip, sl_ip_address_t *sl_ip_address); extern bool device_initialized; static sl_ip_management_t dhcp_type[SLI_SI91X_MAX_INTERFACES] = { 0 }; sl_status_t sl_net_wifi_client_init(sl_net_interface_t interface, const void *configuration, void *context, sl_net_event_handler_t event_handler) { UNUSED_PARAMETER(interface); UNUSED_PARAMETER(context); sl_status_t status = SL_STATUS_FAIL; // Set the user-defined event handler for client mode sl_si91x_register_event_handler(event_handler); status = sl_wifi_init(configuration, NULL, sl_wifi_default_event_handler); // Verify the initialization status and return it VERIFY_STATUS_AND_RETURN(status); return status; } sl_status_t sl_net_wifi_client_deinit(sl_net_interface_t interface) { UNUSED_PARAMETER(interface); return sl_wifi_deinit(); } sl_status_t sl_net_wifi_client_up(sl_net_interface_t interface, sl_net_profile_id_t profile_id) { UNUSED_PARAMETER(interface); sl_status_t status; sl_net_wifi_client_profile_t profile; // Get the client profile using the provided profile_id status = sl_net_get_profile(SL_NET_WIFI_CLIENT_INTERFACE, profile_id, &profile); VERIFY_STATUS_AND_RETURN(status); // Connect to the Wi-Fi network status = sl_wifi_connect(SL_WIFI_CLIENT_INTERFACE, &profile.config, 18000); VERIFY_STATUS_AND_RETURN(status); // Configure the IP address settings status = sl_si91x_configure_ip_address(&profile.ip, SL_SI91X_WIFI_CLIENT_VAP_ID); VERIFY_STATUS_AND_RETURN(status); dhcp_type[SLI_SI91X_CLIENT] = profile.ip.mode; // Set the client profile status = sl_net_set_profile(SL_NET_WIFI_CLIENT_INTERFACE, profile_id, &profile); return status; } sl_status_t sl_net_wifi_client_down(sl_net_interface_t interface) { UNUSED_PARAMETER(interface); // Disconnect from the Wi-Fi network return sl_wifi_disconnect(SL_WIFI_CLIENT_INTERFACE); } sl_status_t sl_net_wifi_ap_init(sl_net_interface_t interface, const void *configuration, const void *workspace, sl_net_event_handler_t event_handler) { UNUSED_PARAMETER(interface); UNUSED_PARAMETER(workspace); sl_status_t status = SL_STATUS_FAIL; // Set the user-defined event handler for AP mode sl_si91x_register_event_handler(event_handler); status = sl_wifi_init(configuration, NULL, sl_wifi_default_event_handler); VERIFY_STATUS_AND_RETURN(status); return status; } sl_status_t sl_net_wifi_ap_deinit(sl_net_interface_t interface) { UNUSED_PARAMETER(interface); return sl_wifi_deinit(); } sl_status_t sl_net_wifi_ap_up(sl_net_interface_t interface, sl_net_profile_id_t profile_id) { UNUSED_PARAMETER(interface); sl_status_t status; sl_net_wifi_ap_profile_t profile; status = sl_net_get_profile(SL_NET_WIFI_AP_INTERFACE, profile_id, &profile); VERIFY_STATUS_AND_RETURN(status); // Validate if profile configuration is valid // AP + DHCP client not supported // AP + link local not supported if (profile.ip.mode != SL_IP_MANAGEMENT_STATIC_IP) { return SL_STATUS_INVALID_CONFIGURATION; } status = sl_si91x_configure_ip_address(&profile.ip, SL_SI91X_WIFI_AP_VAP_ID); VERIFY_STATUS_AND_RETURN(status); dhcp_type[SLI_SI91X_AP] = profile.ip.mode; // Set the AP profile status = sl_net_set_profile(SL_NET_WIFI_AP_INTERFACE, profile_id, &profile); VERIFY_STATUS_AND_RETURN(status); status = sl_wifi_start_ap(SL_WIFI_AP_2_4GHZ_INTERFACE, &profile.config); VERIFY_STATUS_AND_RETURN(status); return status; } sl_status_t sl_net_wifi_ap_down(sl_net_interface_t interface) { UNUSED_PARAMETER(interface); return sl_wifi_stop_ap(SL_WIFI_AP_INTERFACE); } sl_status_t sl_net_join_multicast_address(sl_net_interface_t interface, const sl_ip_address_t *ip_address) { return sli_si91x_send_multicast_request((sl_wifi_interface_t)interface, ip_address, SL_WIFI_MULTICAST_JOIN); } sl_status_t sl_net_leave_multicast_address(sl_net_interface_t interface, const sl_ip_address_t *ip_address) { return sli_si91x_send_multicast_request((sl_wifi_interface_t)interface, ip_address, SL_WIFI_MULTICAST_LEAVE); } static sl_status_t sli_si91x_send_multicast_request(sl_wifi_interface_t interface, const sl_ip_address_t *ip_address, uint8_t command_type) { UNUSED_PARAMETER(interface); si91x_req_multicast_t multicast = { 0 }; sl_status_t status = SL_STATUS_OK; if (!device_initialized) { return SL_STATUS_NOT_INITIALIZED; } //Fill IP version and IP address if (ip_address->type == SL_IPV6) { multicast.ip_version[0] = 6; memcpy(multicast.multicast_address.ipv6_address, ip_address->ip.v6.bytes, RSI_IP_ADDRESS_LEN * 4); } else { multicast.ip_version[0] = 4; memcpy(multicast.multicast_address.ipv4_address, ip_address->ip.v4.bytes, RSI_IP_ADDRESS_LEN); } multicast.type[0] = command_type; status = sl_si91x_driver_send_command(RSI_WLAN_REQ_MULTICAST, SI91X_NETWORK_CMD, &multicast, sizeof(multicast), SL_SI91X_WAIT_FOR_COMMAND_SUCCESS, NULL, NULL); VERIFY_STATUS_AND_RETURN(status); return SL_STATUS_OK; } // Resolve a host name to an IP address using DNS sl_status_t sl_net_dns_resolve_hostname(const char *host_name, const uint32_t timeout, const sl_net_dns_resolution_ip_type_t dns_resolution_ip, sl_ip_address_t *sl_ip_address) { // Check for a NULL pointer for sl_ip_address SL_WIFI_ARGS_CHECK_NULL_POINTER(sl_ip_address); sl_status_t status; sl_si91x_packet_t *packet; sl_wifi_buffer_t *buffer = NULL; const sl_si91x_dns_response_t *dns_response = { 0 }; sl_si91x_dns_query_request_t dns_query_request = { 0 }; // Determine the wait period based on the timeout value sl_si91x_wait_period_t wait_period = timeout == 0 ? SL_SI91X_RETURN_IMMEDIATELY : SL_SI91X_WAIT_FOR_RESPONSE(timeout); // Determine the IP version to be used (IPv4 or IPv6) dns_query_request.ip_version[0] = (dns_resolution_ip == SL_NET_DNS_TYPE_IPV4) ? 4 : 6; memcpy(dns_query_request.url_name, host_name, sizeof(dns_query_request.url_name)); status = sl_si91x_driver_send_command(RSI_WLAN_REQ_DNS_QUERY, SI91X_NETWORK_CMD, &dns_query_request, sizeof(dns_query_request), wait_period, NULL, &buffer); // Check if the command failed and free the buffer if it was allocated if ((status != SL_STATUS_OK) && (buffer != NULL)) { sl_si91x_host_free_buffer(buffer); } VERIFY_STATUS_AND_RETURN(status); // Extract the DNS response from the SI91X packet buffer packet = sl_si91x_host_get_buffer_data(buffer, 0, NULL); dns_response = (sl_si91x_dns_response_t *)packet->data; // Convert the SI91X DNS response to the sl_ip_address format convert_si91x_dns_response(sl_ip_address, dns_response); sl_si91x_host_free_buffer(buffer); return SL_STATUS_OK; } sl_status_t sl_net_set_dns_server(sl_net_interface_t interface, const sl_net_dns_address_t *address) { UNUSED_PARAMETER(interface); sl_status_t status = 0; sli_dns_server_add_request_t dns_server_add_request = { 0 }; if (!device_initialized) { return SL_STATUS_NOT_INITIALIZED; } //! Check for invalid parameters if ((address->primary_server_address && address->primary_server_address->type != SL_IPV4 && address->primary_server_address->type != SL_IPV6) || (address->secondary_server_address && address->secondary_server_address->type != SL_IPV4 && address->secondary_server_address->type != SL_IPV6)) { //! Throw error in case of invalid parameters return SL_STATUS_INVALID_PARAMETER; } //! Set DNS mode dns_server_add_request.dns_mode[0] = (address->primary_server_address == NULL && address->secondary_server_address == NULL) ? 1 /*dhcp*/ : 0 /*static*/; if (address->primary_server_address && address->primary_server_address->type == SL_IPV4) { dns_server_add_request.ip_version[0] = SL_IPV4_VERSION; //! Fill Primary IP address memcpy(dns_server_add_request.sli_ip_address1.primary_dns_ipv4, address->primary_server_address->ip.v4.bytes, SL_IPV4_ADDRESS_LENGTH); } else if (address->primary_server_address && address->primary_server_address->type == SL_IPV6) { dns_server_add_request.ip_version[0] = SL_IPV6_VERSION; //! Fill Primary IP address memcpy(dns_server_add_request.sli_ip_address1.primary_dns_ipv6, address->primary_server_address->ip.v6.bytes, SL_IPV6_ADDRESS_LENGTH); } if (address->secondary_server_address && address->secondary_server_address->type == SL_IPV4) { dns_server_add_request.ip_version[0] = SL_IPV4_VERSION; //! Fill Secondary IP address memcpy(dns_server_add_request.sli_ip_address2.secondary_dns_ipv4, address->secondary_server_address->ip.v4.bytes, SL_IPV4_ADDRESS_LENGTH); } else if (address->secondary_server_address && address->secondary_server_address->type == SL_IPV6) { dns_server_add_request.ip_version[0] = SL_IPV6_VERSION; //! Fill Secondary IP address memcpy(dns_server_add_request.sli_ip_address2.secondary_dns_ipv6, address->secondary_server_address->ip.v6.bytes, SL_IPV6_ADDRESS_LENGTH); } status = sl_si91x_driver_send_command(RSI_WLAN_REQ_DNS_SERVER_ADD, SI91X_NETWORK_CMD, &dns_server_add_request, sizeof(dns_server_add_request), SL_SI91X_WAIT_FOR_COMMAND_SUCCESS, NULL, NULL); return status; } sl_status_t sl_net_configure_ip(sl_net_interface_t interface, const sl_net_ip_configuration_t *ip_config, uint32_t timeout) { uint8_t vap_id = 0; sl_net_ip_configuration_t config = { 0 }; if (SL_NET_WIFI_CLIENT_INTERFACE == SL_NET_INTERFACE_TYPE(interface)) { vap_id = SL_SI91X_WIFI_CLIENT_VAP_ID; dhcp_type[SLI_SI91X_CLIENT] = ip_config->mode; } else if (SL_NET_WIFI_AP_INTERFACE == SL_NET_INTERFACE_TYPE(interface)) { vap_id = SL_SI91X_WIFI_AP_VAP_ID; dhcp_type[SLI_SI91X_AP] = ip_config->mode; } else { return SL_STATUS_WIFI_UNSUPPORTED; } memcpy(&config, ip_config, sizeof(sl_net_ip_configuration_t)); return sli_si91x_configure_ip_address(&config, vap_id, timeout); } sl_status_t sl_net_get_ip_address(sl_net_interface_t interface, sl_net_ip_address_t *ip_address, uint32_t timeout) { uint8_t vap_id = 0; sl_status_t status = 0; sl_net_ip_configuration_t ip_config = { 0 }; if (SL_NET_WIFI_CLIENT_INTERFACE == SL_NET_INTERFACE_TYPE(interface)) { vap_id = SL_SI91X_WIFI_CLIENT_VAP_ID; ip_address->mode = dhcp_type[SLI_SI91X_CLIENT]; } else if (SL_NET_WIFI_AP_INTERFACE == SL_NET_INTERFACE_TYPE(interface)) { vap_id = SL_SI91X_WIFI_AP_VAP_ID; ip_address->mode = dhcp_type[SLI_SI91X_AP]; return SL_STATUS_OK; } else { return SL_STATUS_WIFI_UNSUPPORTED; } ip_config.mode = SL_IP_MANAGEMENT_DHCP; #ifdef SLI_SI91X_ENABLE_IPV6 ip_config.type = SL_IPV6; #else ip_config.type = SL_IPV4; #endif status = sli_si91x_configure_ip_address(&ip_config, vap_id, timeout); if (status != SL_STATUS_OK) { return status; } ip_address->type = ip_config.type; // Copy the IPv4 addresses to the address structure memcpy(ip_address->v4.ip_address.bytes, (const uint8_t *)ip_config.ip.v4.ip_address.bytes, sizeof(sl_ipv4_address_t)); memcpy(ip_address->v4.netmask.bytes, (const uint8_t *)ip_config.ip.v4.netmask.bytes, sizeof(sl_ipv4_address_t)); memcpy(ip_address->v4.gateway.bytes, (const uint8_t *)ip_config.ip.v4.gateway.bytes, sizeof(sl_ipv4_address_t)); // Copy the IPv6 addresses to the address structure memcpy(&ip_address->v6.link_local_address.bytes, (const uint8_t *)ip_config.ip.v6.link_local_address.bytes, sizeof(sl_ipv6_address_t)); memcpy(&ip_address->v6.global_address.bytes, (const uint8_t *)ip_config.ip.v6.global_address.bytes, sizeof(sl_ipv6_address_t)); memcpy(&ip_address->v6.gateway.bytes, (const uint8_t *)ip_config.ip.v6.gateway.bytes, sizeof(sl_ipv6_address_t)); return SL_STATUS_OK; }