288 lines
7.5 KiB
C
288 lines
7.5 KiB
C
/**
|
|
* Copyright (2018) Baidu Inc. All rights reserved.
|
|
*
|
|
* 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.
|
|
*/
|
|
/**
|
|
* File: lightduer_smart_config.c
|
|
* Auth: Chen Xihao (chenxihao@baidu.com)
|
|
* Desc: Duer smart config function file.
|
|
*/
|
|
|
|
#include "lightduer_smart_config.h"
|
|
#ifdef __linux__
|
|
#include <errno.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/socket.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#else
|
|
/* #include <sockets.h> */
|
|
#include "lwip/sockets.h"
|
|
#endif
|
|
#include "lightduer_smart_config_decode.h"
|
|
#include "lightduer_log.h"
|
|
#include "lightduer_lib.h"
|
|
#include "lightduer_memory.h"
|
|
#include "lightduer_timestamp.h"
|
|
#include "lightduer_sleep.h"
|
|
|
|
#define DEFAULT_ACK_UDP_PORT 10001
|
|
#define SMART_CONFIG_ACK_TIMEOUT 10000 // ms
|
|
#define ACK_SEND_COUNTS 50
|
|
|
|
static const char *SMARTCONFIG_VERSION = "1.0";
|
|
static volatile int s_ack_stop_flag = 0;
|
|
duer_sc_status_t duer_smart_config_recv_packet(duer_sc_context_t context,
|
|
uint8_t *packet, uint32_t len)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
duer_sc_status_t status = DUER_SC_STATUS_IDLE;
|
|
|
|
if (priv == NULL) {
|
|
DUER_LOGE("invalid arguments");
|
|
return status;
|
|
}
|
|
|
|
if (len < sizeof(duer_ieee80211_frame_t)) {
|
|
DUER_LOGE("invalid packet, len %u", len);
|
|
return status;
|
|
}
|
|
|
|
if (priv->status == DUER_SC_STATUS_COMPLETE) {
|
|
return DUER_SC_STATUS_COMPLETE;
|
|
}
|
|
|
|
status = duer_sc_packet_decode(priv, packet, len);
|
|
|
|
if (status == DUER_SC_STATUS_COMPLETE &&
|
|
priv->status < DUER_SC_STATUS_COMPLETE) {
|
|
DUER_LOGI("complete ssid: %s pwd: %s random: %d",
|
|
priv->result.ssid, priv->result.pwd, priv->result.random);
|
|
} else if (status == DUER_SC_STATUS_LOCKED_CHAN && priv->status != status) {
|
|
DUER_LOGI("channel locked");
|
|
uint8_t *ap_mac = NULL;
|
|
duer_ieee80211_frame_t *frame = (duer_ieee80211_frame_t *)packet;
|
|
int dir = frame->frame_ctl[1] & DUER_IEEE80211_FC1_DIR_MASK;
|
|
|
|
if (dir == DUER_IEEE80211_FC1_DIR_NODS) {
|
|
ap_mac = frame->addr3;
|
|
} else if (dir == DUER_IEEE80211_FC1_DIR_FROMDS) {
|
|
ap_mac = frame->addr2;
|
|
} else {
|
|
ap_mac = frame->addr1;
|
|
}
|
|
|
|
DUER_MEMCPY(priv->ap_mac, ap_mac, sizeof(priv->ap_mac));
|
|
|
|
priv->lock_channel_time = duer_timestamp();
|
|
#ifdef DUER_MODULE_DEVICE_STATUS_SUPPORT
|
|
priv->log_lock_channel = 1;
|
|
#endif
|
|
} else if (status == DUER_SC_STATUS_LOCKED_CHAN &&
|
|
DUER_TIME_AFTER(duer_timestamp(),
|
|
priv->lock_channel_time + DUER_LOCK_CHANNEL_TIMEOUT)) {
|
|
// TODO: we should search channel again
|
|
DUER_LOGE("lock channel timeout");
|
|
priv->lock_channel_time = duer_timestamp();
|
|
}
|
|
|
|
priv->status = status;
|
|
|
|
return status;
|
|
}
|
|
|
|
int duer_smart_config_switch_channel(duer_sc_context_t context, int channel)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
if (priv) {
|
|
priv->cur_channel = channel;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
duer_sc_status_t duer_smart_config_get_status(duer_sc_context_t context)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
|
|
if (priv == NULL) {
|
|
return DUER_SC_STATUS_IDLE;
|
|
}
|
|
|
|
return priv->status;
|
|
}
|
|
|
|
duer_sc_context_t duer_smart_config_init(void)
|
|
{
|
|
duer_smartconfig_priv_t *priv = NULL;
|
|
int ret = 0;
|
|
|
|
priv = (duer_smartconfig_priv_t *)DUER_MALLOC(sizeof(duer_smartconfig_priv_t));
|
|
if (priv == NULL) {
|
|
DUER_LOGE("malloc failed!");
|
|
return NULL;
|
|
}
|
|
|
|
DUER_MEMSET(priv, 0, sizeof(duer_smartconfig_priv_t));
|
|
|
|
priv->status = DUER_SC_STATUS_SEARCH_CHAN;
|
|
|
|
return priv;
|
|
}
|
|
|
|
int duer_smart_config_deinit(duer_sc_context_t context)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
|
|
if (priv == NULL) {
|
|
DUER_LOGE("invalid arguments");
|
|
return -1;
|
|
}
|
|
|
|
#ifdef DUER_MODULE_DEVICE_STATUS_SUPPORT
|
|
duer_ds_log_smart_cfg_finished(&priv->info);
|
|
#endif
|
|
|
|
DUER_FREE(priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int duer_smart_config_get_result(duer_sc_context_t context,
|
|
duer_wifi_config_result_t *result)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
|
|
if (!result) {
|
|
DUER_LOGE("invalid arguments");
|
|
return -1;
|
|
}
|
|
|
|
if (priv == NULL) {
|
|
DUER_LOGI("has already stoped!");
|
|
return -1;
|
|
}
|
|
|
|
DUER_MEMCPY(result, &priv->result, sizeof(*result));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef DUER_MODULE_DEVICE_STATUS_SUPPORT
|
|
void duer_smart_config_send_log(duer_sc_context_t context)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
if (priv) {
|
|
if (priv->log_lock_channel) {
|
|
duer_ds_log_smart_cfg(DUER_DS_LOG_SMART_CFG_LOCK_CHANNEL, NULL);
|
|
priv->log_lock_channel = 0;
|
|
}
|
|
|
|
if (priv->log_lead_completed) {
|
|
duer_ds_log_smart_cfg_lead_completed(priv->lead_code.data_len);
|
|
priv->log_lead_completed = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
int duer_smart_config_get_ap_mac(duer_sc_context_t context, uint8_t *ap_mac)
|
|
{
|
|
duer_smartconfig_priv_t *priv = (duer_smartconfig_priv_t *)context;
|
|
|
|
if (priv == NULL || ap_mac == NULL) {
|
|
DUER_LOGE("invalid arguments");
|
|
return -1;
|
|
}
|
|
|
|
if (priv->status < DUER_SC_STATUS_LOCKED_CHAN) {
|
|
DUER_LOGE("channel has not been locked");
|
|
return -1;
|
|
}
|
|
|
|
DUER_MEMCPY(ap_mac, priv->ap_mac, sizeof(priv->ap_mac));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int duer_smart_config_ack(uint32_t port, uint8_t random)
|
|
{
|
|
struct sockaddr_in addr;
|
|
uint32_t end_time = 0;
|
|
int ack_count = 0;
|
|
int socketfd = -1;
|
|
int tmp = 1;
|
|
int ret = 0;
|
|
int i = 0;
|
|
|
|
DUER_LOGI("ack start");
|
|
|
|
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
|
|
if (socketfd < 0) {
|
|
DUER_LOGE("create socket fail");
|
|
return -1;
|
|
}
|
|
|
|
if (port == 0) {
|
|
port = DEFAULT_ACK_UDP_PORT;
|
|
}
|
|
DUER_LOGI("ack port %d", port);
|
|
|
|
DUER_MEMSET(&addr, 0, sizeof(addr));
|
|
|
|
addr.sin_port = htons(port);
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
|
|
|
s_ack_stop_flag = 0;
|
|
end_time = duer_timestamp() + SMART_CONFIG_ACK_TIMEOUT;
|
|
|
|
ret = setsockopt(socketfd, SOL_SOCKET, SO_BROADCAST, &tmp, sizeof(tmp));
|
|
if (ret < 0) {
|
|
DUER_LOGE("setsockopt error");
|
|
close(socketfd);
|
|
return -1;
|
|
}
|
|
|
|
while (s_ack_stop_flag == 0 && DUER_TIME_BEFORE(duer_timestamp(), end_time)) {
|
|
ret = sendto(socketfd, &random, 1, 0, (struct sockaddr *)&addr, sizeof(addr));
|
|
if (ret > 0) {
|
|
DUER_LOGD("ack send");
|
|
if (ack_count++ >= ACK_SEND_COUNTS) {
|
|
break;
|
|
}
|
|
} else {
|
|
int err = 0;
|
|
uint32_t optlen = sizeof(err);
|
|
|
|
if (getsockopt(socketfd, SOL_SOCKET, SO_ERROR, &err, &optlen) < 0) {
|
|
DUER_LOGE("getsockopt failed");
|
|
}
|
|
DUER_LOGE("udp send error, %d", err);
|
|
}
|
|
duer_sleep(20);
|
|
}
|
|
|
|
close(socketfd);
|
|
|
|
DUER_LOGI("ack end");
|
|
|
|
return 0;
|
|
}
|
|
|
|
void duer_smart_config_stop_ack(void)
|
|
{
|
|
s_ack_stop_flag = 1;
|
|
}
|