303 lines
7.2 KiB
C
303 lines
7.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/if.h>
|
|
|
|
#include <easy_setup.h>
|
|
#include <scan.h>
|
|
|
|
#define ES_TARGET_VERSION "v4.0.0"
|
|
|
|
//#define QUERY_TIMEOUT_MS (30*1000) /* replaced with easy_setup_timeout_s */
|
|
#define QUERY_INTERVAL_MS (1000)
|
|
|
|
#define WLAN_IFACE "wlan0"
|
|
|
|
#define PARAM_MAX_LEN (256)
|
|
#define RESULT_MAX_LEN (256)
|
|
|
|
#define WLC_GET_VAR (262)
|
|
#define WLC_SET_VAR (263)
|
|
|
|
#define DEFAULT_PROTOCOL_MASK (0x3) /* mcast */
|
|
uint16 g_protocol_mask = 0; /* default no protocols enabled */
|
|
|
|
/* Linux network driver ioctl encoding */
|
|
typedef struct wl_ioctl {
|
|
uint cmd; /* common ioctl definition */
|
|
void *buf; /* pointer to user buffer */
|
|
uint len; /* length of user buffer */
|
|
unsigned char set; /* 1=set IOCTL; 0=query IOCTL */
|
|
uint used; /* bytes read or written (optional) */
|
|
uint needed; /* bytes needed (optional) */
|
|
} wl_ioctl_t;
|
|
|
|
static int g_ioc_fd = -1; /* socket fd */
|
|
static uint8 g_debug = 0;
|
|
static easy_setup_result_t g_result;
|
|
static uint8 g_protocol = 0;
|
|
extern int killed;
|
|
static int easy_setup_timeout_s = 60; /* -1 stands for infinity */
|
|
|
|
int easy_setup_start() {
|
|
int i;
|
|
int ret = 0;
|
|
|
|
LOGE("Easy setup target library %s\n", ES_TARGET_VERSION);
|
|
|
|
int found = 0;
|
|
for (i=0; i<EASY_SETUP_PROTO_MAX; i++) {
|
|
if (g_protocol_mask & (1<<i)) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
g_protocol_mask = DEFAULT_PROTOCOL_MASK;
|
|
}
|
|
|
|
/* open socket to kernel */
|
|
if ((g_ioc_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
LOGE("create control socket failed: %d(%s)\n", errno, strerror(errno));
|
|
return -1;
|
|
}
|
|
|
|
easy_setup_param_t* p = (easy_setup_param_t*) malloc(PARAM_MAX_LEN);
|
|
memset(p, 0, PARAM_MAX_LEN);
|
|
p->enable = EASY_SETUP_START;
|
|
p->protocol_mask = g_protocol_mask;
|
|
|
|
int param_len = 0;
|
|
param_len += ((uint8*)&p->param-(uint8*)p);
|
|
|
|
tlv_t* t = &p->param;
|
|
easy_setup_get_param(g_protocol_mask, &t);
|
|
|
|
if ((ret = easy_setup_iovar(1, p, (uint8*) t - (uint8*) p)) < 0) {
|
|
LOGE("easy setup start failed: %d(%s)\n",
|
|
errno, strerror(errno));
|
|
}
|
|
|
|
free(p);
|
|
return ret;
|
|
}
|
|
|
|
int easy_setup_stop() {
|
|
int ret = 0;
|
|
|
|
if (g_ioc_fd < 0) {
|
|
LOGE("easy setup query: control socket not initialized.\n");
|
|
return -1;
|
|
}
|
|
|
|
easy_setup_param_t param;
|
|
memset(¶m, 0, sizeof(param));
|
|
param.enable = EASY_SETUP_STOP;
|
|
param.protocol_mask = 0;
|
|
|
|
if ((ret = easy_setup_iovar(1, ¶m, sizeof(param))) < 0) {
|
|
LOGE("easy setup stop failed: %d(%s)\n",
|
|
errno, strerror(errno));
|
|
}
|
|
|
|
close(g_ioc_fd);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* query result is of tlv format
|
|
* type = protocol shot
|
|
* length = result length
|
|
* value = mcast_result_t/akiss_result_t ... */
|
|
int easy_setup_query() {
|
|
int ret = 0;
|
|
tlv_t* query = NULL;
|
|
|
|
if (g_ioc_fd < 0) {
|
|
LOGE("easy setup query: control socket not initialized.\n");
|
|
return -1;
|
|
}
|
|
|
|
query = (tlv_t*) malloc(RESULT_MAX_LEN);
|
|
|
|
if (!query) {
|
|
LOGE("failed allocating result buffer.\n");
|
|
return -1;
|
|
}
|
|
|
|
uint last_state = 0;
|
|
int total_time_ms = 0;
|
|
while (!killed) {
|
|
usleep(QUERY_INTERVAL_MS * 1000);
|
|
|
|
ret = easy_setup_iovar(0, query, RESULT_MAX_LEN);
|
|
if (ret < 0) {
|
|
LOGE("easy setup query failed: %d(%s)\n", errno, strerror(errno));
|
|
free(query);
|
|
return -1;
|
|
} else {
|
|
int i;
|
|
|
|
/* copy common part of result to easy_setup_result_t */
|
|
memcpy(&g_result, query->value, sizeof(g_result));
|
|
if (last_state != g_result.state) {
|
|
LOGD("state: %d --> %d\n", last_state, g_result.state);
|
|
last_state = g_result.state;
|
|
if (last_state == EASY_SETUP_STATE_DONE) {
|
|
g_protocol = query->type;
|
|
easy_setup_set_result(g_protocol, query->value);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (easy_setup_timeout_s > 0) {
|
|
total_time_ms += QUERY_INTERVAL_MS;
|
|
if (total_time_ms >= easy_setup_timeout_s*1000) {
|
|
LOGE("timeout (%d)\n", easy_setup_timeout_s);
|
|
free(query);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
free(query);
|
|
|
|
if (killed) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int easy_setup_iovar(int set, void* param, int size) {
|
|
int ret = 0;
|
|
char* cmd = "easy_setup";
|
|
int cmd_len = strlen(cmd)+1;
|
|
int tot_len = cmd_len+size;
|
|
uint8* ptr = (uint8*) malloc(tot_len);
|
|
if (!ptr) {
|
|
LOGE("easy setup iovar: malloc failed\n");
|
|
return -1;
|
|
}
|
|
|
|
strcpy(ptr, cmd);
|
|
memcpy(ptr+cmd_len, param, size);
|
|
|
|
ret = easy_setup_ioctl(set?WLC_SET_VAR:WLC_GET_VAR, set, ptr, tot_len);
|
|
|
|
/* for iovar get, copy back data */
|
|
if (!set) {
|
|
memcpy(param, ptr, size);
|
|
}
|
|
|
|
free(ptr);
|
|
return ret;
|
|
}
|
|
|
|
int easy_setup_ioctl(int cmd, int set, void* param, int size) {
|
|
struct ifreq ifr;
|
|
wl_ioctl_t ioc;
|
|
int ret = 0;
|
|
|
|
if (g_ioc_fd < 0) {
|
|
LOGE("easy setup ioctl: control socket not initialized.\n");
|
|
return -1;
|
|
}
|
|
|
|
ioc.cmd = cmd;
|
|
ioc.buf = param;
|
|
ioc.len = size;
|
|
ioc.set = set;
|
|
|
|
strncpy(ifr.ifr_name, WLAN_IFACE, IFNAMSIZ);
|
|
ifr.ifr_name[IFNAMSIZ-1] = 0;
|
|
ifr.ifr_data = (caddr_t) &ioc;
|
|
|
|
if ((ret = ioctl(g_ioc_fd, SIOCDEVPRIVATE, &ifr)) < 0) {
|
|
/* log if not WLC_SCAN_RESULTS(51) */
|
|
if (cmd != 51) {
|
|
LOGD("easy setup ioctl(cmd=%d) failed: %d(%s)\n",
|
|
cmd, errno, strerror(errno));
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void easy_setup_set_timeout(int s) {
|
|
easy_setup_timeout_s = s;
|
|
}
|
|
|
|
int easy_setup_get_ssid(char buff[], int buff_len) {
|
|
int i;
|
|
easy_setup_result_t* r = &g_result;
|
|
|
|
if (r->state != EASY_SETUP_STATE_DONE) {
|
|
LOGE("easy setup data unavailable\n");
|
|
return -1;
|
|
}
|
|
|
|
if (buff_len < r->ap_ssid.len+1) {
|
|
LOGE("insufficient buffer provided: %d < %d\n", buff_len, r->ap_ssid.len+1);
|
|
return -1;
|
|
}
|
|
|
|
for (i=0; i<r->ap_ssid.len; i++) {
|
|
buff[i] = r->ap_ssid.val[i];
|
|
}
|
|
buff[i] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int easy_setup_get_password(char buff[], int buff_len) {
|
|
int i;
|
|
easy_setup_result_t* r = &g_result;
|
|
|
|
if (r->state != EASY_SETUP_STATE_DONE) {
|
|
LOGE("easy setup data unavailable\n");
|
|
return -1;
|
|
}
|
|
|
|
if (buff_len < r->security_key_length+1) {
|
|
LOGE("insufficient buffer provided: %d < %d\n", buff_len, r->security_key_length+1);
|
|
return -1;
|
|
}
|
|
|
|
for (i=0; i<r->security_key_length; i++) {
|
|
buff[i] = r->security_key[i];
|
|
}
|
|
buff[i] = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int easy_setup_get_protocol(uint8* protocol) {
|
|
int i;
|
|
easy_setup_result_t* r = &g_result;
|
|
|
|
if (r->state != EASY_SETUP_STATE_DONE) {
|
|
LOGE("easy setup data unavailable\n");
|
|
return -1;
|
|
}
|
|
|
|
*protocol = g_protocol;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int easy_setup_get_security() {
|
|
if (g_result.state != EASY_SETUP_STATE_DONE) {
|
|
LOGE("easy setup data unavailable\n");
|
|
return -1;
|
|
}
|
|
|
|
return scan_and_get_security(&g_result.ap_ssid);
|
|
}
|