a75be3413e
These changes guarantee that the SSID and Passphrase received via protocomm are NULL terminated and size limited to their standard lengths. List of changes: * Corrected length of passphrase field in wifi_prov_config_set_data_t structure * Performing length checks on SSID, passphrase and bssid, when populating wifi_prov_config_set_data_t structure with received credentials
343 lines
13 KiB
C
343 lines
13 KiB
C
// Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <esp_err.h>
|
|
#include <esp_log.h>
|
|
|
|
#include "wifi_constants.pb-c.h"
|
|
#include "wifi_config.pb-c.h"
|
|
|
|
#include <wifi_provisioning/wifi_config.h>
|
|
|
|
static const char* TAG = "WiFiProvConfig";
|
|
|
|
typedef struct wifi_prov_config_cmd {
|
|
int cmd_num;
|
|
esp_err_t (*command_handler)(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data);
|
|
} wifi_prov_config_cmd_t;
|
|
|
|
static esp_err_t cmd_get_status_handler(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data);
|
|
|
|
static esp_err_t cmd_set_config_handler(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data);
|
|
|
|
static esp_err_t cmd_apply_config_handler(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data);
|
|
|
|
static wifi_prov_config_cmd_t cmd_table[] = {
|
|
{
|
|
.cmd_num = WI_FI_CONFIG_MSG_TYPE__TypeCmdGetStatus,
|
|
.command_handler = cmd_get_status_handler
|
|
},
|
|
{
|
|
.cmd_num = WI_FI_CONFIG_MSG_TYPE__TypeCmdSetConfig,
|
|
.command_handler = cmd_set_config_handler
|
|
},
|
|
{
|
|
.cmd_num = WI_FI_CONFIG_MSG_TYPE__TypeCmdApplyConfig,
|
|
.command_handler = cmd_apply_config_handler
|
|
}
|
|
};
|
|
|
|
static esp_err_t cmd_get_status_handler(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data)
|
|
{
|
|
ESP_LOGD(TAG, "Enter cmd_get_status_handler");
|
|
wifi_prov_config_handlers_t *h = (wifi_prov_config_handlers_t *) priv_data;
|
|
if (!h) {
|
|
ESP_LOGE(TAG, "Command invoked without handlers");
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
RespGetStatus *resp_payload = (RespGetStatus *) malloc(sizeof(RespGetStatus));
|
|
if (!resp_payload) {
|
|
ESP_LOGE(TAG, "Error allocating memory");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
resp_get_status__init(resp_payload);
|
|
|
|
wifi_prov_config_get_data_t resp_data;
|
|
if (h->get_status_handler(&resp_data, &h->ctx) == ESP_OK) {
|
|
if (resp_data.wifi_state == WIFI_PROV_STA_CONNECTING) {
|
|
resp_payload->sta_state = WIFI_STATION_STATE__Connecting;
|
|
resp_payload->state_case = RESP_GET_STATUS__STATE_CONNECTED;
|
|
} else if (resp_data.wifi_state == WIFI_PROV_STA_CONNECTED) {
|
|
resp_payload->sta_state = WIFI_STATION_STATE__Connected;
|
|
resp_payload->state_case = RESP_GET_STATUS__STATE_CONNECTED;
|
|
WifiConnectedState *connected = (WifiConnectedState *)(
|
|
malloc(sizeof(WifiConnectedState)));
|
|
if (!connected) {
|
|
ESP_LOGE(TAG, "Error allocating memory");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
resp_payload->connected = connected;
|
|
wifi_connected_state__init(connected);
|
|
|
|
connected->ip4_addr = strdup(resp_data.conn_info.ip_addr);
|
|
if (connected->ip4_addr == NULL) {
|
|
free(resp_payload);
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
connected->bssid.len = sizeof(resp_data.conn_info.bssid);
|
|
connected->bssid.data = (uint8_t *) strndup(resp_data.conn_info.bssid,
|
|
sizeof(resp_data.conn_info.bssid));
|
|
if (connected->bssid.data == NULL) {
|
|
free(connected->ip4_addr);
|
|
free(resp_payload);
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
connected->ssid.len = strlen(resp_data.conn_info.ssid);
|
|
connected->ssid.data = (uint8_t *) strdup(resp_data.conn_info.ssid);
|
|
if (connected->ssid.data == NULL) {
|
|
free(connected->bssid.data);
|
|
free(connected->ip4_addr);
|
|
free(resp_payload);
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
connected->channel = resp_data.conn_info.channel;
|
|
connected->auth_mode = resp_data.conn_info.auth_mode;
|
|
} else if (resp_data.wifi_state == WIFI_PROV_STA_DISCONNECTED) {
|
|
resp_payload->sta_state = WIFI_STATION_STATE__ConnectionFailed;
|
|
resp_payload->state_case = RESP_GET_STATUS__STATE_FAIL_REASON;
|
|
|
|
if (resp_data.fail_reason == WIFI_PROV_STA_AUTH_ERROR) {
|
|
resp_payload->fail_reason = WIFI_CONNECT_FAILED_REASON__AuthError;
|
|
} else if (resp_data.fail_reason == WIFI_PROV_STA_AP_NOT_FOUND) {
|
|
resp_payload->fail_reason = WIFI_CONNECT_FAILED_REASON__NetworkNotFound;
|
|
}
|
|
}
|
|
resp_payload->status = STATUS__Success;
|
|
}
|
|
|
|
resp->payload_case = WI_FI_CONFIG_PAYLOAD__PAYLOAD_RESP_GET_STATUS;
|
|
resp->resp_get_status = resp_payload;
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t cmd_set_config_handler(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data)
|
|
{
|
|
ESP_LOGD(TAG, "Enter cmd_set_config_handler");
|
|
wifi_prov_config_handlers_t *h = (wifi_prov_config_handlers_t *) priv_data;
|
|
if (!h) {
|
|
ESP_LOGE(TAG, "Command invoked without handlers");
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
RespSetConfig *resp_payload = (RespSetConfig *) malloc(sizeof(RespSetConfig));
|
|
if (resp_payload == NULL) {
|
|
ESP_LOGE(TAG, "Error allocating memory");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
resp_set_config__init(resp_payload);
|
|
|
|
wifi_prov_config_set_data_t req_data;
|
|
memset(&req_data, 0, sizeof(req_data));
|
|
|
|
/* Check arguments provided in protobuf packet:
|
|
* - SSID / Passphrase string length must be within the standard limits
|
|
* - BSSID must either be NULL or have length equal to that imposed by the standard
|
|
* If any of these conditions are not satisfied, don't invoke the handler and
|
|
* send error status without closing connection */
|
|
resp_payload->status = STATUS__InvalidArgument;
|
|
if (req->cmd_set_config->bssid.len != 0 &&
|
|
req->cmd_set_config->bssid.len != sizeof(req_data.bssid)) {
|
|
ESP_LOGD(TAG, "Received invalid BSSID");
|
|
} else if (req->cmd_set_config->ssid.len >= sizeof(req_data.ssid)) {
|
|
ESP_LOGD(TAG, "Received invalid SSID");
|
|
} else if (req->cmd_set_config->passphrase.len >= sizeof(req_data.password)) {
|
|
ESP_LOGD(TAG, "Received invalid Passphrase");
|
|
} else {
|
|
/* The received SSID and Passphrase are not NULL terminated so
|
|
* we memcpy over zeroed out arrays. Above length checks ensure
|
|
* that there is atleast 1 extra byte for null termination */
|
|
memcpy(req_data.ssid, req->cmd_set_config->ssid.data,
|
|
req->cmd_set_config->ssid.len);
|
|
memcpy(req_data.password, req->cmd_set_config->passphrase.data,
|
|
req->cmd_set_config->passphrase.len);
|
|
memcpy(req_data.bssid, req->cmd_set_config->bssid.data,
|
|
req->cmd_set_config->bssid.len);
|
|
req_data.channel = req->cmd_set_config->channel;
|
|
if (h->set_config_handler(&req_data, &h->ctx) == ESP_OK) {
|
|
resp_payload->status = STATUS__Success;
|
|
} else {
|
|
resp_payload->status = STATUS__InternalError;
|
|
}
|
|
}
|
|
|
|
resp->payload_case = WI_FI_CONFIG_PAYLOAD__PAYLOAD_RESP_SET_CONFIG;
|
|
resp->resp_set_config = resp_payload;
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t cmd_apply_config_handler(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data)
|
|
{
|
|
ESP_LOGD(TAG, "Enter cmd_apply_config_handler");
|
|
wifi_prov_config_handlers_t *h = (wifi_prov_config_handlers_t *) priv_data;
|
|
if (!h) {
|
|
ESP_LOGE(TAG, "Command invoked without handlers");
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
RespApplyConfig *resp_payload = (RespApplyConfig *) malloc(sizeof(RespApplyConfig));
|
|
if (!resp_payload) {
|
|
ESP_LOGE(TAG, "Error allocating memory");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
resp_apply_config__init(resp_payload);
|
|
|
|
if (h->apply_config_handler(&h->ctx) == ESP_OK) {
|
|
resp_payload->status = STATUS__Success;
|
|
} else {
|
|
resp_payload->status = STATUS__InternalError;
|
|
}
|
|
|
|
resp->payload_case = WI_FI_CONFIG_PAYLOAD__PAYLOAD_RESP_APPLY_CONFIG;
|
|
resp->resp_apply_config = resp_payload;
|
|
return ESP_OK;
|
|
}
|
|
|
|
static int lookup_cmd_handler(int cmd_id)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < sizeof(cmd_table)/sizeof(wifi_prov_config_cmd_t); i++) {
|
|
if (cmd_table[i].cmd_num == cmd_id) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
static void wifi_prov_config_command_cleanup(WiFiConfigPayload *resp, void *priv_data)
|
|
{
|
|
if (!resp) {
|
|
return;
|
|
}
|
|
|
|
switch (resp->msg) {
|
|
case WI_FI_CONFIG_MSG_TYPE__TypeRespGetStatus:
|
|
{
|
|
switch (resp->resp_get_status->sta_state) {
|
|
case WIFI_STATION_STATE__Connecting:
|
|
break;
|
|
case WIFI_STATION_STATE__Connected:
|
|
if (resp->resp_get_status->connected) {
|
|
if (resp->resp_get_status->connected->ip4_addr) {
|
|
free(resp->resp_get_status->connected->ip4_addr);
|
|
}
|
|
if (resp->resp_get_status->connected->bssid.data) {
|
|
free(resp->resp_get_status->connected->bssid.data);
|
|
}
|
|
if (resp->resp_get_status->connected->ssid.data) {
|
|
free(resp->resp_get_status->connected->ssid.data);
|
|
}
|
|
free(resp->resp_get_status->connected);
|
|
}
|
|
break;
|
|
case WIFI_STATION_STATE__ConnectionFailed:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
free(resp->resp_get_status);
|
|
}
|
|
break;
|
|
case WI_FI_CONFIG_MSG_TYPE__TypeRespSetConfig:
|
|
{
|
|
free(resp->resp_set_config);
|
|
}
|
|
break;
|
|
case WI_FI_CONFIG_MSG_TYPE__TypeRespApplyConfig:
|
|
{
|
|
free(resp->resp_apply_config);
|
|
}
|
|
break;
|
|
default:
|
|
ESP_LOGE(TAG, "Unsupported response type in cleanup_handler");
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static esp_err_t wifi_prov_config_command_dispatcher(WiFiConfigPayload *req,
|
|
WiFiConfigPayload *resp, void *priv_data)
|
|
{
|
|
esp_err_t ret;
|
|
|
|
ESP_LOGD(TAG, "In wifi_prov_config_command_dispatcher Cmd=%d", req->msg);
|
|
|
|
int cmd_index = lookup_cmd_handler(req->msg);
|
|
if (cmd_index < 0) {
|
|
ESP_LOGE(TAG, "Invalid command handler lookup");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
ret = cmd_table[cmd_index].command_handler(req, resp, priv_data);
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "Error executing command handler");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t wifi_prov_config_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen,
|
|
uint8_t **outbuf, ssize_t *outlen, void *priv_data)
|
|
{
|
|
WiFiConfigPayload *req;
|
|
WiFiConfigPayload resp;
|
|
esp_err_t ret;
|
|
|
|
req = wi_fi_config_payload__unpack(NULL, inlen, inbuf);
|
|
if (!req) {
|
|
ESP_LOGE(TAG, "Unable to unpack config data");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
wi_fi_config_payload__init(&resp);
|
|
ret = wifi_prov_config_command_dispatcher(req, &resp, priv_data);
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGE(TAG, "Proto command dispatcher error %d", ret);
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
resp.msg = req->msg + 1; /* Response is request + 1 */
|
|
wi_fi_config_payload__free_unpacked(req, NULL);
|
|
|
|
*outlen = wi_fi_config_payload__get_packed_size(&resp);
|
|
if (*outlen <= 0) {
|
|
ESP_LOGE(TAG, "Invalid encoding for response");
|
|
return ESP_FAIL;
|
|
}
|
|
|
|
*outbuf = (uint8_t *) malloc(*outlen);
|
|
if (!*outbuf) {
|
|
ESP_LOGE(TAG, "System out of memory");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
wi_fi_config_payload__pack(&resp, *outbuf);
|
|
wifi_prov_config_command_cleanup(&resp, priv_data);
|
|
|
|
return ESP_OK;
|
|
}
|