mbed-os/connectivity/drivers/emac/COMPONENT_WHD/interface/WhdSoftAPInterface.cpp

238 lines
8.1 KiB
C++

/*
* Copyright (c) 2018-2019 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsapi.h"
#include "lwipopts.h"
#include "WhdSoftAPInterface.h"
#include "nsapi.h"
#include "lwipopts.h"
#include "lwip/etharp.h"
#include "lwip/ethip6.h"
#include "rtos.h"
#include "whd_emac.h"
#include "whd_wifi_api.h"
extern int whd_toerror(whd_result_t res);
extern nsapi_security_t whd_tosecurity(whd_security_t sec);
extern whd_security_t whd_fromsecurity(nsapi_security_t sec);
extern "C" void whd_emac_wifi_link_state_changed(whd_interface_t ifp, whd_bool_t state_up);
static const whd_event_num_t ap_events[] = { WLC_E_LINK, WLC_E_IF, WLC_E_DEAUTH, WLC_E_DEAUTH_IND, WLC_E_DISASSOC, WLC_E_DISASSOC_IND, WLC_E_ASSOC_IND, WLC_E_REASSOC_IND, WLC_E_NONE };
static void *whd_default_handle_softap_events(whd_interface_t ifp, const whd_event_header_t *event_header,
const uint8_t *event_data, void *handler_user_data)
{
whd_driver_t whd_driver = ifp->whd_driver;
UNUSED_PARAMETER(event_header);
UNUSED_PARAMETER(event_data);
UNUSED_PARAMETER(handler_user_data);
WHD_IOCTL_LOG_ADD_EVENT(whd_driver, event_header->event_type, event_header->flags, event_header->reason);
if ((event_header->event_type == (whd_event_num_t)WLC_E_LINK) ||
(event_header->event_type == WLC_E_IF)) {
if (osSemaphoreGetCount(whd_driver->ap_info.whd_wifi_sleep_flag) < 1) {
osStatus_t result = osSemaphoreRelease(whd_driver->ap_info.whd_wifi_sleep_flag);
if (result != osOK) {
printf("Release whd_wifi_sleep_flag ERROR: %d", result);
}
}
}
return handler_user_data;
}
WhdSoftAPInterface::WhdSoftAPInterface(WHD_EMAC &emac, OnboardNetworkStack &stack, whd_interface_shared_info_t &shared)
: EMACInterface(emac, stack),
_whd_emac(emac),
_iface_shared(shared)
{
}
int WhdSoftAPInterface::start(const char *ssid, const char *pass, nsapi_security_t security, uint8_t channel,
bool start_dhcp_server, const whd_custom_ie_info_t *ie_info, bool ap_sta_concur)
{
ScopedMutexLock lock(_iface_shared.mutex);
nsapi_error_t err;
// power up primary emac interface first
if (ap_sta_concur) {
WHD_EMAC &emac_prime = WHD_EMAC::get_instance(WHD_STA_ROLE);
if (!emac_prime.power_up()) {
printf("Primary interface power up ERROR!\n");
return NSAPI_ERROR_DEVICE_ERROR;
}
}
// set concurrency mode and power up secondary, the bsp init is done by primary emac
_whd_emac.ap_sta_concur = ap_sta_concur;
if (!_whd_emac.power_up()) {
printf("Secondary interface power up ERROR!\n");
return NSAPI_ERROR_DEVICE_ERROR;
}
// setup ssid
whd_ssid_t whd_ssid;
strncpy((char *)whd_ssid.value, ssid, SSID_NAME_SIZE);
whd_ssid.value[SSID_NAME_SIZE - 1] = '\0';
whd_ssid.length = strlen((char *)whd_ssid.value);
// choose network security
whd_security_t whd_security = whd_fromsecurity(security);
/* set up the AP info */
err = whd_wifi_init_ap(_whd_emac.ifp, &whd_ssid, whd_security, (const uint8_t *)pass,
strlen(pass), channel);
if (err != NSAPI_ERROR_OK) {
printf("whd_wifi_init_ap() ERROR: %d\n", err);
return err;
}
// update default softap interface event handler
err = unregister_event_handler();
if (err != NSAPI_ERROR_OK) {
printf("unregister_event_handler() ERROR: %d\n", err);
return err;
}
err = register_event_handler(whd_default_handle_softap_events);
if (err != NSAPI_ERROR_OK) {
printf("register_event_handler() ERROR: %d\n", err);
return err;
}
_iface_shared.if_status_flags |= IF_STATUS_SOFT_AP_UP;
if (!ap_sta_concur || (_iface_shared.default_if_cfg == DEFAULT_IF_NOT_SET)) {
_iface_shared.default_if_cfg = DEFAULT_IF_SOFT_AP;
}
if (!_interface) {
nsapi_error_t err = _stack.add_ethernet_interface(_whd_emac, _iface_shared.default_if_cfg == DEFAULT_IF_SOFT_AP, &_interface);
if (err != NSAPI_ERROR_OK) {
_interface = NULL;
return err;
}
_interface->attach(_connection_status_cb);
_iface_shared.iface_softap = _interface;
} else if (_iface_shared.default_if_cfg == DEFAULT_IF_SOFT_AP) {
_stack.set_default_interface(_interface);
}
if (ie_info) {
err = whd_wifi_manage_custom_ie(_whd_emac.ifp, WHD_ADD_CUSTOM_IE, (const uint8_t *)ie_info->oui,
ie_info->subtype, (const void *)ie_info->data, ie_info->length, ie_info->which_packets);
if (err != NSAPI_ERROR_OK) {
printf("whd_wifi_manage_custom_ie() ERROR: %d\n", err);
return err;
}
}
err = whd_wifi_start_ap(_whd_emac.ifp);
if (err != NSAPI_ERROR_OK) {
printf("whd_wifi_start_ap() ERROR: %d\n", err);
return err;
}
// Set static IP address for SoftAP and bring up
set_dhcp(false);
if (whd_wifi_is_ready_to_transceive(_whd_emac.ifp) == WHD_SUCCESS) {
whd_emac_wifi_link_state_changed(_whd_emac.ifp, WHD_TRUE);
}
err = _interface->bringup(_dhcp,
_ip_address[0] ? _ip_address : 0,
_netmask[0] ? _netmask : 0,
_gateway[0] ? _gateway : 0,
DEFAULT_STACK);
if (err != NSAPI_ERROR_OK) {
printf("bringup() ERROR: %d\n", err);
}
if (start_dhcp_server) {
_dhcp_server = std::make_unique<CyDhcpServer>(get_stack(), this);
if (CY_RSLT_SUCCESS != _dhcp_server->start()) {
err = NSAPI_ERROR_DHCP_FAILURE;
}
}
return err;
}
int WhdSoftAPInterface::stop(void)
{
ScopedMutexLock lock(_iface_shared.mutex);
if (_dhcp_server && CY_RSLT_SUCCESS != _dhcp_server->stop()) {
return NSAPI_ERROR_DHCP_FAILURE;
}
_dhcp_server.reset();
// bring down
int err = _interface->bringdown();
if (err) {
return err;
}
_iface_shared.if_status_flags &= ~IF_STATUS_SOFT_AP_UP;
if ((_iface_shared.if_status_flags & IF_STATUS_STA_UP) == 0) {
_iface_shared.default_if_cfg = DEFAULT_IF_NOT_SET;
}
// stop softap
whd_result_t res = whd_wifi_stop_ap(_whd_emac.ifp);
if (res != WHD_SUCCESS) {
return whd_toerror(res);
}
// remove the interface added in start
if (_interface) {
nsapi_error_t err = _stack.remove_ethernet_interface(&_interface);
if (err != NSAPI_ERROR_OK) {
return err;
}
_iface_shared.iface_softap = NULL;
}
return NSAPI_ERROR_OK;
}
int WhdSoftAPInterface::remove_custom_ie(const whd_custom_ie_info_t *ie_info)
{
return whd_wifi_manage_custom_ie(_whd_emac.ifp, WHD_REMOVE_CUSTOM_IE, (const uint8_t *)ie_info->oui,
ie_info->subtype, (const void *)ie_info->data, ie_info->length, ie_info->which_packets);
}
int WhdSoftAPInterface::get_associated_client_list(void *client_list_buffer, uint16_t buffer_length)
{
return whd_wifi_get_associated_client_list(_whd_emac.ifp, client_list_buffer, buffer_length);
}
int WhdSoftAPInterface::register_event_handler(whd_event_handler_t softap_event_handler)
{
uint16_t ap_events_entry = _whd_emac.ifp->event_reg_list[WHD_AP_EVENT_ENTRY];
return whd_management_set_event_handler(_whd_emac.ifp, ap_events, softap_event_handler, NULL, &ap_events_entry);
}
int WhdSoftAPInterface::unregister_event_handler(void)
{
return whd_wifi_deregister_event_handler(_whd_emac.ifp, _whd_emac.ifp->event_reg_list[WHD_AP_EVENT_ENTRY]);
}