wifi: eswifi: Add access point offload support

The eswifi controller is capable of acting as an Access Point.
Implement ap_enable/ap_disable methods.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
This commit is contained in:
Loic Poulain 2019-01-03 11:01:05 +01:00 committed by Anas Nashif
commit 8a7b6ffaab
2 changed files with 158 additions and 11 deletions

View file

@ -52,6 +52,7 @@ struct eswifi_sta {
enum eswifi_security_type security; enum eswifi_security_type security;
char pass[65]; char pass[65];
bool connected; bool connected;
uint8_t channel;
}; };
struct eswifi_bus_ops; struct eswifi_bus_ops;

View file

@ -435,15 +435,9 @@ static int eswifi_mgmt_disconnect(struct device *dev)
return 0; return 0;
} }
static int eswifi_mgmt_connect(struct device *dev, static int __eswifi_sta_config(struct eswifi_dev *eswifi,
struct wifi_connect_req_params *params) struct wifi_connect_req_params *params)
{ {
struct eswifi_dev *eswifi = dev->driver_data;
LOG_DBG("");
eswifi_lock(eswifi);
memcpy(eswifi->sta.ssid, params->ssid, params->ssid_length); memcpy(eswifi->sta.ssid, params->ssid, params->ssid_length);
eswifi->sta.ssid[params->ssid_length] = '\0'; eswifi->sta.ssid[params->ssid_length] = '\0';
@ -458,13 +452,163 @@ static int eswifi_mgmt_connect(struct device *dev,
eswifi->sta.security = ESWIFI_SEC_WPA2_MIXED; eswifi->sta.security = ESWIFI_SEC_WPA2_MIXED;
break; break;
default: default:
LOG_ERR("Unsupported security type %d", params->security);
eswifi_unlock(eswifi);
return -EINVAL; return -EINVAL;
} }
eswifi->req = ESWIFI_REQ_CONNECT; if (params->channel == WIFI_CHANNEL_ANY) {
k_work_submit_to_queue(&eswifi->work_q, &eswifi->request_work); eswifi->sta.channel = 0;
} else {
eswifi->sta.channel = params->channel;
}
return 0;
}
static int eswifi_mgmt_connect(struct device *dev,
struct wifi_connect_req_params *params)
{
struct eswifi_dev *eswifi = dev->driver_data;
int err;
LOG_DBG("");
eswifi_lock(eswifi);
err = __eswifi_sta_config(eswifi, params);
if (!err) {
eswifi->req = ESWIFI_REQ_CONNECT;
k_work_submit_to_queue(&eswifi->work_q,
&eswifi->request_work);
}
eswifi_unlock(eswifi);
return err;
}
#if defined(CONFIG_NET_IPV4)
static int eswifi_mgmt_ap_enable(struct device *dev,
struct wifi_connect_req_params *params)
{
struct eswifi_dev *eswifi = dev->driver_data;
struct net_if_ipv4 *ipv4 = eswifi->iface->config.ip.ipv4;
struct net_if_addr *unicast = NULL;
int err = -EIO, i;
LOG_DBG("");
eswifi_lock(eswifi);
if (eswifi->role == ESWIFI_ROLE_AP) {
err = -EALREADY;
goto error;
}
err = __eswifi_sta_config(eswifi, params);
if (err) {
goto error;
}
/* security */
snprintf(eswifi->buf, sizeof(eswifi->buf), "A1=%u\r",
eswifi->sta.security);
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set Security");
goto error;
}
/* Passkey */
if (eswifi->sta.security != ESWIFI_SEC_OPEN) {
snprintf(eswifi->buf, sizeof(eswifi->buf), "A2=%s\r",
eswifi->sta.pass);
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set passkey");
goto error;
}
}
/* Set SSID (0=no MAC, 1=append MAC) */
snprintf(eswifi->buf, sizeof(eswifi->buf), "AS=0,%s\r",
eswifi->sta.ssid);
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set SSID");
goto error;
}
/* Set Channel */
snprintf(eswifi->buf, sizeof(eswifi->buf), "AC=%u\r",
eswifi->sta.channel);
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to set Channel");
goto error;
}
/* Set IP Address */
for (i = 0; ipv4 && i < NET_IF_MAX_IPV4_ADDR; i++) {
if (ipv4->unicast[i].is_used) {
unicast = &ipv4->unicast[i];
break;
}
}
if (!unicast) {
LOG_ERR("No IPv4 assigned for AP mode");
err = -EADDRNOTAVAIL;
goto error;
}
snprintf(eswifi->buf, sizeof(eswifi->buf), "Z6=%s\r",
net_sprint_ipv4_addr(&unicast->address.in_addr));
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to active access point");
goto error;
}
/* Enable AP */
snprintf(eswifi->buf, sizeof(eswifi->buf), "AD\r");
err = eswifi_at_cmd(eswifi, eswifi->buf);
if (err < 0) {
LOG_ERR("Unable to active access point");
goto error;
}
eswifi->role = ESWIFI_ROLE_AP;
eswifi_unlock(eswifi);
return 0;
error:
eswifi_unlock(eswifi);
return err;
}
#else
static int eswifi_mgmt_ap_enable(struct device *dev,
struct wifi_connect_req_params *params)
{
LOG_ERR("IPv4 requested for AP mode");
return -ENOTSUP;
}
#endif /* CONFIG_NET_IPV4 */
static int eswifi_mgmt_ap_disable(struct device *dev)
{
struct eswifi_dev *eswifi = dev->driver_data;
char cmd[] = "AE\r";
int err;
eswifi_lock(eswifi);
err = eswifi_at_cmd(eswifi, cmd);
if (err < 0) {
eswifi_unlock(eswifi);
return -EIO;
}
eswifi->role = ESWIFI_ROLE_CLIENT;
eswifi_unlock(eswifi); eswifi_unlock(eswifi);
@ -520,6 +664,8 @@ static const struct net_wifi_mgmt_offload eswifi_offload_api = {
.scan = eswifi_mgmt_scan, .scan = eswifi_mgmt_scan,
.connect = eswifi_mgmt_connect, .connect = eswifi_mgmt_connect,
.disconnect = eswifi_mgmt_disconnect, .disconnect = eswifi_mgmt_disconnect,
.ap_enable = eswifi_mgmt_ap_enable,
.ap_disable = eswifi_mgmt_ap_disable,
}; };
NET_DEVICE_OFFLOAD_INIT(eswifi_mgmt, CONFIG_WIFI_ESWIFI_NAME, NET_DEVICE_OFFLOAD_INIT(eswifi_mgmt, CONFIG_WIFI_ESWIFI_NAME,