mirror of
https://dev.iopsys.eu/hal/wifimngr.git
synced 2025-12-20 01:11:11 +08:00
365 lines
9.2 KiB
C
365 lines
9.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* wps.c - provides "wifi.wps" ubus object
|
|
*
|
|
* Copyright (C) 2018-2024 Iopsys Software Solutions AB. All rights reserved.
|
|
* Copyright (C) 2025 Genexis AB.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <libubox/blobmsg.h>
|
|
#include <libubox/blobmsg_json.h>
|
|
#include <libubox/uloop.h>
|
|
#include <libubox/ustream.h>
|
|
#include <libubox/utils.h>
|
|
#include <libubus.h>
|
|
#include <uci.h>
|
|
|
|
#include <easy/easy.h>
|
|
#include <wifi.h>
|
|
#include "wifimngr.h"
|
|
|
|
#include "policy.c"
|
|
|
|
char *wifi_get_main_interface(struct wifimngr *w, int freq_band, char *ifmain)
|
|
{
|
|
enum wifi_bw bw;
|
|
int i;
|
|
|
|
for (i = 0; i < w->num_wifi_device; i++) {
|
|
uint32_t ch = 0;
|
|
|
|
if (!wifi_get_channel(w->wdev[i].phy, &ch, &bw)) {
|
|
if (freq_band == 5 && (ch >= 36 && ch < 200)) {
|
|
strncpy(ifmain, w->wdev[i].phy, 15);
|
|
return ifmain;
|
|
} else if (freq_band == 2 && (ch > 0 && ch <= 14)) {
|
|
strncpy(ifmain, w->wdev[i].phy, 15);
|
|
return ifmain;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int wps_status(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
struct wifimngr *w = container_of(obj, struct wifimngr, wifi_wps_obj);
|
|
struct blob_attr *tb[__ATTR_IFNAME_ONLY];
|
|
enum wps_status code = 0;
|
|
char ifname[16] = {0};
|
|
struct blob_buf bb;
|
|
char status[16];
|
|
|
|
memset(&bb, 0, sizeof(bb));
|
|
blobmsg_parse(ifname_policy, __ATTR_IFNAME_ONLY, tb, blob_data(msg),
|
|
blob_len(msg));
|
|
|
|
if (!(tb[WPS_ATTR_IFNAME])) {
|
|
if (wifi_get_main_interface(w, 5, ifname) == NULL)
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
} else {
|
|
strncpy(ifname, blobmsg_data(tb[WPS_ATTR_IFNAME]), 15);
|
|
}
|
|
|
|
if (wifi_get_wps_status(ifname, &code))
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
switch (code) {
|
|
case WPS_STATUS_INIT:
|
|
strcpy(status, "init");
|
|
break;
|
|
case WPS_STATUS_PROCESSING:
|
|
strcpy(status, "processing");
|
|
break;
|
|
case WPS_STATUS_SUCCESS:
|
|
strcpy(status, "success");
|
|
break;
|
|
case WPS_STATUS_FAIL:
|
|
strcpy(status, "fail");
|
|
break;
|
|
case WPS_STATUS_TIMEOUT:
|
|
strcpy(status, "timeout");
|
|
break;
|
|
default:
|
|
strcpy(status, "unknown");
|
|
break;
|
|
}
|
|
|
|
blob_buf_init(&bb, 0);
|
|
blobmsg_add_u32(&bb, "code", code);
|
|
blobmsg_add_string(&bb, "status", status);
|
|
ubus_send_reply(ctx, req, bb.head);
|
|
blob_buf_free(&bb);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wps_start(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
struct wifimngr *w = container_of(obj, struct wifimngr, wifi_wps_obj);
|
|
struct blob_attr *tb[__WPS_START_ATTR_MAX];
|
|
struct wps_param wps = {
|
|
.role = WPS_REGISTRAR,
|
|
.method = WPS_METHOD_PBC
|
|
};
|
|
char ifname[16] = {0};
|
|
char role[16] = {0};
|
|
char mode[8] = {0};
|
|
unsigned long pin;
|
|
|
|
blobmsg_parse(wps_start_policy, __WPS_START_ATTR_MAX,
|
|
tb, blob_data(msg), blob_len(msg));
|
|
|
|
if (!(tb[WPS_START_ATTR_IFNAME])) {
|
|
/* if interface not provided, assume 5Ghz main interface */
|
|
if (wifi_get_main_interface(w, 5, ifname) == NULL)
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
} else {
|
|
strncpy(ifname, blobmsg_data(tb[WPS_START_ATTR_IFNAME]), 15);
|
|
}
|
|
|
|
if (!(tb[WPS_START_ATTR_MODE])) {
|
|
wps.method = WPS_METHOD_PBC;
|
|
} else {
|
|
strncpy(mode, blobmsg_data(tb[WPS_START_ATTR_MODE]), 7);
|
|
if (!strcasecmp(mode, "pin"))
|
|
wps.method = WPS_METHOD_PIN;
|
|
else if (!strcasecmp(mode, "pbc"))
|
|
wps.method = WPS_METHOD_PBC;
|
|
else
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (!(tb[WPS_START_ATTR_ROLE])) {
|
|
wps.role = WPS_REGISTRAR;
|
|
} else {
|
|
strncpy(role, blobmsg_data(tb[WPS_START_ATTR_ROLE]), 10);
|
|
if (!strcasecmp(role, "registrar"))
|
|
wps.role = WPS_REGISTRAR;
|
|
else if (!strcasecmp(role, "enrollee"))
|
|
wps.role = WPS_ENROLLEE;
|
|
else if (!strcasecmp(role, "bsta"))
|
|
wps.role = WPS_ENROLLEE_BSTA;
|
|
else
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
if (wps.method == WPS_METHOD_PIN) {
|
|
if (!(tb[WPS_START_ATTR_STA_PIN])) {
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
} else {
|
|
pin = strtoul(blobmsg_data(tb[WPS_START_ATTR_STA_PIN]), NULL, 10);
|
|
if (!wifi_is_wps_pin_valid(pin))
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
wps.pin = pin;
|
|
}
|
|
}
|
|
|
|
if ((wifi_start_wps(ifname, wps) == 0))
|
|
return UBUS_STATUS_OK;
|
|
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
}
|
|
|
|
static int wps_genpin(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
unsigned long PIN;
|
|
char local_devPwd[32];
|
|
struct blob_buf bb;
|
|
|
|
memset(&bb, 0, sizeof(bb));
|
|
|
|
wifi_generate_wps_pin(&PIN);
|
|
sprintf(local_devPwd, "%08u", (unsigned int)PIN);
|
|
local_devPwd[8] = '\0';
|
|
|
|
blob_buf_init(&bb, 0);
|
|
blobmsg_add_string(&bb, "pin", local_devPwd);
|
|
ubus_send_reply(ctx, req, bb.head);
|
|
blob_buf_free(&bb);
|
|
|
|
return UBUS_STATUS_OK;
|
|
}
|
|
|
|
static int wps_checkpin(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
unsigned long pin;
|
|
bool valid = false;
|
|
struct blob_attr *tb[__ATTR_PIN_MAX];
|
|
struct blob_buf bb;
|
|
|
|
memset(&bb, 0, sizeof(bb));
|
|
blobmsg_parse(pin_policy, __ATTR_PIN_MAX, tb, blob_data(msg),
|
|
blob_len(msg));
|
|
|
|
if (!(tb[ATTR_PIN]))
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
|
pin = strtoul(blobmsg_get_string(tb[ATTR_PIN]), NULL, 10);
|
|
valid = wifi_is_wps_pin_valid(pin);
|
|
|
|
blob_buf_init(&bb, 0);
|
|
blobmsg_add_u8(&bb, "valid", valid);
|
|
ubus_send_reply(ctx, req, bb.head);
|
|
blob_buf_free(&bb);
|
|
|
|
return UBUS_STATUS_OK;
|
|
}
|
|
|
|
int wps_set_ap_pin(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
struct wifimngr *w = container_of(obj, struct wifimngr, wifi_wps_obj);
|
|
struct blob_attr *tb[__PIN_SET_MAX];
|
|
char ifname[16] = {0};
|
|
unsigned long pin;
|
|
|
|
blobmsg_parse(pin_set_policy, __PIN_SET_MAX, tb, blob_data(msg),
|
|
blob_len(msg));
|
|
|
|
if (!(tb[PIN_SET_IFNAME])) {
|
|
if (wifi_get_main_interface(w, 5, ifname) == NULL)
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
} else {
|
|
strncpy(ifname, blobmsg_data(tb[PIN_SET_IFNAME]), 15);
|
|
}
|
|
|
|
if (!(tb[PIN_SET_PIN]))
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
|
pin = strtoul(blobmsg_data(tb[PIN_SET_PIN]), NULL, 10);
|
|
if (!wifi_is_wps_pin_valid(pin))
|
|
return UBUS_STATUS_INVALID_ARGUMENT;
|
|
|
|
if (wifi_set_wps_pin(ifname, pin))
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
return UBUS_STATUS_OK;
|
|
}
|
|
|
|
static int wps_show_ap_pin(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
struct wifimngr *w = container_of(obj, struct wifimngr, wifi_wps_obj);
|
|
struct blob_attr *tb[__ATTR_IFNAME_ONLY];
|
|
char ifname[16] = {0};
|
|
char pinstr[9] = {0};
|
|
struct blob_buf bb;
|
|
unsigned long pin;
|
|
|
|
memset(&bb, 0, sizeof(bb));
|
|
blobmsg_parse(ifname_policy, __ATTR_IFNAME_ONLY, tb, blob_data(msg),
|
|
blob_len(msg));
|
|
|
|
if (!(tb[WPS_ATTR_IFNAME])) {
|
|
if (wifi_get_main_interface(w, 5, ifname) == NULL)
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
} else {
|
|
strncpy(ifname, blobmsg_data(tb[WPS_ATTR_IFNAME]), 15);
|
|
}
|
|
|
|
if (wifi_get_wps_pin(ifname, &pin))
|
|
return UBUS_STATUS_UNKNOWN_ERROR;
|
|
|
|
blob_buf_init(&bb, 0);
|
|
sprintf(pinstr, "%08lu", pin);
|
|
blobmsg_add_string(&bb, "pin", pinstr);
|
|
ubus_send_reply(ctx, req, bb.head);
|
|
blob_buf_free(&bb);
|
|
|
|
return UBUS_STATUS_OK;
|
|
}
|
|
|
|
int wps_stop(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
struct wifimngr *w = container_of(obj, struct wifimngr, wifi_wps_obj);
|
|
struct blob_attr *tb[__ATTR_IFNAME_ONLY];
|
|
char ifname[16] = {0};
|
|
int i;
|
|
|
|
blobmsg_parse(ifname_policy, __ATTR_IFNAME_ONLY, tb, blob_data(msg),
|
|
blob_len(msg));
|
|
|
|
if (tb[WPS_ATTR_IFNAME]) {
|
|
strncpy(ifname, blobmsg_data(tb[WPS_ATTR_IFNAME]), 15);
|
|
wifi_stop_wps(ifname);
|
|
} else {
|
|
for (i = 0; i < w->num_wifi_iface; i++) {
|
|
wifi_stop_wps(w->ifs[i].iface);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wl_wps_help(struct ubus_context *ctx, struct ubus_object *obj,
|
|
struct ubus_request_data *req, const char *method,
|
|
struct blob_attr *msg)
|
|
{
|
|
return wl_help_command(ctx, obj, req, method, msg, "wifi.wps");
|
|
}
|
|
|
|
#define MAX_WPS_METHODS 10
|
|
int add_wps_methods(struct wifimngr *w, struct ubus_object *wifi_wps_obj)
|
|
{
|
|
struct ubus_method *wps_methods;
|
|
int n_methods = 0;
|
|
|
|
wps_methods = calloc(MAX_WPS_METHODS, sizeof(struct ubus_method));
|
|
if (!wps_methods)
|
|
return -ENOMEM;
|
|
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD_NOARG("help", wl_wps_help));
|
|
|
|
/* Usage -
|
|
* start {"mode":"pbc|pin", "role":"enrollee|registrar", "pin":"pin"}
|
|
* where default mode = pbc and default role = registrar.
|
|
* If role = registrar, and mode = pin, then enrollee's pin
|
|
* should be provided through the 'pin' attribute.
|
|
*/
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD("start", wps_start, wps_start_policy));
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD_NOARG("stop", wps_stop));
|
|
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD("status", wps_status, ifname_policy));
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD_NOARG("generate_pin", wps_genpin));
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD("validate_pin", wps_checkpin, pin_policy));
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD("showpin", wps_show_ap_pin, ifname_policy));
|
|
|
|
UBUS_METHOD_ADD(wps_methods, n_methods,
|
|
UBUS_METHOD("setpin", wps_set_ap_pin, pin_set_policy));
|
|
|
|
|
|
wifi_wps_obj->methods = wps_methods;
|
|
wifi_wps_obj->n_methods = n_methods;
|
|
|
|
return 0;
|
|
}
|