openwrt: add aditional source files

This commit is contained in:
sinavir 2025-02-11 10:24:13 +01:00
parent 5ace39b0a4
commit ba99627140
No known key found for this signature in database
6 changed files with 3324 additions and 0 deletions

715
hostapd/radius.c Normal file
View file

@ -0,0 +1,715 @@
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "ap/ap_config.h"
#include "eap_server/eap.h"
#include "radius/radius.h"
#include "radius/radius_server.h"
#include "eap_register.h"
#include <libubox/blobmsg_json.h>
#include <libubox/blobmsg.h>
#include <libubox/avl.h>
#include <libubox/avl-cmp.h>
#include <libubox/kvlist.h>
#include <sys/stat.h>
#include <fnmatch.h>
#define VENDOR_ID_WISPR 14122
#define VENDOR_ATTR_SIZE 6
struct radius_parse_attr_data {
unsigned int vendor;
u8 type;
int size;
char format;
const char *data;
};
struct radius_parse_attr_state {
struct hostapd_radius_attr *prev;
struct hostapd_radius_attr *attr;
struct wpabuf *buf;
void *attrdata;
};
struct radius_user_state {
struct avl_node node;
struct eap_user data;
};
struct radius_user_data {
struct kvlist users;
struct avl_tree user_state;
struct blob_attr *wildcard;
};
struct radius_state {
struct radius_server_data *radius;
struct eap_config eap;
struct radius_user_data phase1, phase2;
const char *user_file;
time_t user_file_ts;
int n_attrs;
struct hostapd_radius_attr *attrs;
};
struct radius_config {
struct tls_connection_params tls;
struct radius_server_conf radius;
};
enum {
USER_ATTR_PASSWORD,
USER_ATTR_HASH,
USER_ATTR_SALT,
USER_ATTR_METHODS,
USER_ATTR_RADIUS,
USER_ATTR_VLAN,
USER_ATTR_MAX_RATE_UP,
USER_ATTR_MAX_RATE_DOWN,
__USER_ATTR_MAX
};
static void radius_tls_event(void *ctx, enum tls_event ev,
union tls_event_data *data)
{
switch (ev) {
case TLS_CERT_CHAIN_SUCCESS:
wpa_printf(MSG_DEBUG, "radius: remote certificate verification success");
break;
case TLS_CERT_CHAIN_FAILURE:
wpa_printf(MSG_INFO, "radius: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'",
data->cert_fail.reason,
data->cert_fail.depth,
data->cert_fail.subject,
data->cert_fail.reason_txt);
break;
case TLS_PEER_CERTIFICATE:
wpa_printf(MSG_DEBUG, "radius: peer certificate: depth=%d serial_num=%s subject=%s",
data->peer_cert.depth,
data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A",
data->peer_cert.subject);
break;
case TLS_ALERT:
if (data->alert.is_local)
wpa_printf(MSG_DEBUG, "radius: local TLS alert: %s",
data->alert.description);
else
wpa_printf(MSG_DEBUG, "radius: remote TLS alert: %s",
data->alert.description);
break;
case TLS_UNSAFE_RENEGOTIATION_DISABLED:
/* Not applicable to TLS server */
break;
}
}
static void radius_userdata_init(struct radius_user_data *u)
{
kvlist_init(&u->users, kvlist_blob_len);
avl_init(&u->user_state, avl_strcmp, false, NULL);
}
static void radius_userdata_free(struct radius_user_data *u)
{
struct radius_user_state *s, *tmp;
kvlist_free(&u->users);
free(u->wildcard);
u->wildcard = NULL;
avl_remove_all_elements(&u->user_state, s, node, tmp)
free(s);
}
static void
radius_userdata_load(struct radius_user_data *u, struct blob_attr *data)
{
enum {
USERSTATE_USERS,
USERSTATE_WILDCARD,
__USERSTATE_MAX,
};
static const struct blobmsg_policy policy[__USERSTATE_MAX] = {
[USERSTATE_USERS] = { "users", BLOBMSG_TYPE_TABLE },
[USERSTATE_WILDCARD] = { "wildcard", BLOBMSG_TYPE_ARRAY },
};
struct blob_attr *tb[__USERSTATE_MAX], *cur;
int rem;
if (!data)
return;
blobmsg_parse(policy, __USERSTATE_MAX, tb, blobmsg_data(data), blobmsg_len(data));
blobmsg_for_each_attr(cur, tb[USERSTATE_USERS], rem)
kvlist_set(&u->users, blobmsg_name(cur), cur);
if (tb[USERSTATE_WILDCARD])
u->wildcard = blob_memdup(tb[USERSTATE_WILDCARD]);
}
static void
load_userfile(struct radius_state *s)
{
enum {
USERDATA_PHASE1,
USERDATA_PHASE2,
__USERDATA_MAX
};
static const struct blobmsg_policy policy[__USERDATA_MAX] = {
[USERDATA_PHASE1] = { "phase1", BLOBMSG_TYPE_TABLE },
[USERDATA_PHASE2] = { "phase2", BLOBMSG_TYPE_TABLE },
};
struct blob_attr *tb[__USERDATA_MAX], *cur;
static struct blob_buf b;
struct stat st;
int rem;
if (stat(s->user_file, &st))
return;
if (s->user_file_ts == st.st_mtime)
return;
s->user_file_ts = st.st_mtime;
radius_userdata_free(&s->phase1);
radius_userdata_free(&s->phase2);
blob_buf_init(&b, 0);
blobmsg_add_json_from_file(&b, s->user_file);
blobmsg_parse(policy, __USERDATA_MAX, tb, blob_data(b.head), blob_len(b.head));
radius_userdata_load(&s->phase1, tb[USERDATA_PHASE1]);
radius_userdata_load(&s->phase2, tb[USERDATA_PHASE2]);
blob_buf_free(&b);
}
static struct blob_attr *
radius_user_get(struct radius_user_data *s, const char *name)
{
struct blob_attr *cur;
int rem;
cur = kvlist_get(&s->users, name);
if (cur)
return cur;
blobmsg_for_each_attr(cur, s->wildcard, rem) {
static const struct blobmsg_policy policy = {
"name", BLOBMSG_TYPE_STRING
};
struct blob_attr *pattern;
if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
continue;
blobmsg_parse(&policy, 1, &pattern, blobmsg_data(cur), blobmsg_len(cur));
if (!name)
continue;
if (!fnmatch(blobmsg_get_string(pattern), name, 0))
return cur;
}
return NULL;
}
static struct radius_parse_attr_data *
radius_parse_attr(struct blob_attr *attr)
{
static const struct blobmsg_policy policy[4] = {
{ .type = BLOBMSG_TYPE_INT32 },
{ .type = BLOBMSG_TYPE_INT32 },
{ .type = BLOBMSG_TYPE_STRING },
{ .type = BLOBMSG_TYPE_STRING },
};
static struct radius_parse_attr_data data;
struct blob_attr *tb[4];
const char *format;
blobmsg_parse_array(policy, ARRAY_SIZE(policy), tb, blobmsg_data(attr), blobmsg_len(attr));
if (!tb[0] || !tb[1] || !tb[2] || !tb[3])
return NULL;
format = blobmsg_get_string(tb[2]);
if (strlen(format) != 1)
return NULL;
data.vendor = blobmsg_get_u32(tb[0]);
data.type = blobmsg_get_u32(tb[1]);
data.format = format[0];
data.data = blobmsg_get_string(tb[3]);
data.size = strlen(data.data);
switch (data.format) {
case 's':
break;
case 'x':
if (data.size & 1)
return NULL;
data.size /= 2;
break;
case 'd':
data.size = 4;
break;
default:
return NULL;
}
return &data;
}
static void
radius_count_attrs(struct blob_attr **tb, int *n_attr, size_t *attr_size)
{
struct blob_attr *data = tb[USER_ATTR_RADIUS];
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, data, rem) {
struct radius_parse_attr_data *data;
size_t prev = *attr_size;
data = radius_parse_attr(cur);
if (!data)
continue;
*attr_size += data->size;
if (data->vendor)
*attr_size += VENDOR_ATTR_SIZE;
(*n_attr)++;
}
*n_attr += !!tb[USER_ATTR_VLAN] * 3 +
!!tb[USER_ATTR_MAX_RATE_UP] +
!!tb[USER_ATTR_MAX_RATE_DOWN];
*attr_size += !!tb[USER_ATTR_VLAN] * (4 + 4 + 5) +
!!tb[USER_ATTR_MAX_RATE_UP] * (4 + VENDOR_ATTR_SIZE) +
!!tb[USER_ATTR_MAX_RATE_DOWN] * (4 + VENDOR_ATTR_SIZE);
}
static void *
radius_add_attr(struct radius_parse_attr_state *state,
u32 vendor, u8 type, u8 len)
{
struct hostapd_radius_attr *attr;
struct wpabuf *buf;
void *val;
val = state->attrdata;
buf = state->buf++;
buf->buf = val;
attr = state->attr++;
attr->val = buf;
attr->type = type;
if (state->prev)
state->prev->next = attr;
state->prev = attr;
if (vendor) {
u8 *vendor_hdr = val + 4;
WPA_PUT_BE32(val, vendor);
vendor_hdr[0] = type;
vendor_hdr[1] = len + 2;
len += VENDOR_ATTR_SIZE;
val += VENDOR_ATTR_SIZE;
attr->type = RADIUS_ATTR_VENDOR_SPECIFIC;
}
buf->size = buf->used = len;
state->attrdata += len;
return val;
}
static void
radius_parse_attrs(struct blob_attr **tb, struct radius_parse_attr_state *state)
{
struct blob_attr *data = tb[USER_ATTR_RADIUS];
struct hostapd_radius_attr *prev = NULL;
struct blob_attr *cur;
int len, rem;
void *val;
if ((cur = tb[USER_ATTR_VLAN]) != NULL && blobmsg_get_u32(cur) < 4096) {
char buf[5];
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_TYPE, 4);
WPA_PUT_BE32(val, RADIUS_TUNNEL_TYPE_VLAN);
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, 4);
WPA_PUT_BE32(val, RADIUS_TUNNEL_MEDIUM_TYPE_802);
len = snprintf(buf, sizeof(buf), "%d", blobmsg_get_u32(cur));
val = radius_add_attr(state, 0, RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, len);
memcpy(val, buf, len);
}
if ((cur = tb[USER_ATTR_MAX_RATE_UP]) != NULL) {
val = radius_add_attr(state, VENDOR_ID_WISPR, 7, 4);
WPA_PUT_BE32(val, blobmsg_get_u32(cur));
}
if ((cur = tb[USER_ATTR_MAX_RATE_DOWN]) != NULL) {
val = radius_add_attr(state, VENDOR_ID_WISPR, 8, 4);
WPA_PUT_BE32(val, blobmsg_get_u32(cur));
}
blobmsg_for_each_attr(cur, data, rem) {
struct radius_parse_attr_data *data;
void *val;
int size;
data = radius_parse_attr(cur);
if (!data)
continue;
val = radius_add_attr(state, data->vendor, data->type, data->size);
switch (data->format) {
case 's':
memcpy(val, data->data, data->size);
break;
case 'x':
hexstr2bin(data->data, val, data->size);
break;
case 'd':
WPA_PUT_BE32(val, atoi(data->data));
break;
}
}
}
static void
radius_user_parse_methods(struct eap_user *eap, struct blob_attr *data)
{
struct blob_attr *cur;
int rem, n = 0;
if (!data)
return;
blobmsg_for_each_attr(cur, data, rem) {
const char *method;
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
continue;
if (n == EAP_MAX_METHODS)
break;
method = blobmsg_get_string(cur);
eap->methods[n].method = eap_server_get_type(method, &eap->methods[n].vendor);
if (eap->methods[n].vendor == EAP_VENDOR_IETF &&
eap->methods[n].method == EAP_TYPE_NONE) {
if (!strcmp(method, "TTLS-PAP")) {
eap->ttls_auth |= EAP_TTLS_AUTH_PAP;
continue;
}
if (!strcmp(method, "TTLS-CHAP")) {
eap->ttls_auth |= EAP_TTLS_AUTH_CHAP;
continue;
}
if (!strcmp(method, "TTLS-MSCHAP")) {
eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
continue;
}
if (!strcmp(method, "TTLS-MSCHAPV2")) {
eap->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
continue;
}
}
n++;
}
}
static struct eap_user *
radius_user_get_state(struct radius_user_data *u, struct blob_attr *data,
const char *id)
{
static const struct blobmsg_policy policy[__USER_ATTR_MAX] = {
[USER_ATTR_PASSWORD] = { "password", BLOBMSG_TYPE_STRING },
[USER_ATTR_HASH] = { "hash", BLOBMSG_TYPE_STRING },
[USER_ATTR_SALT] = { "salt", BLOBMSG_TYPE_STRING },
[USER_ATTR_METHODS] = { "methods", BLOBMSG_TYPE_ARRAY },
[USER_ATTR_RADIUS] = { "radius", BLOBMSG_TYPE_ARRAY },
[USER_ATTR_VLAN] = { "vlan-id", BLOBMSG_TYPE_INT32 },
[USER_ATTR_MAX_RATE_UP] = { "max-rate-up", BLOBMSG_TYPE_INT32 },
[USER_ATTR_MAX_RATE_DOWN] = { "max-rate-down", BLOBMSG_TYPE_INT32 },
};
struct blob_attr *tb[__USER_ATTR_MAX], *cur;
char *password_buf, *salt_buf, *name_buf;
struct radius_parse_attr_state astate = {};
struct hostapd_radius_attr *attr;
struct radius_user_state *state;
int pw_len = 0, salt_len = 0;
struct eap_user *eap;
struct wpabuf *val;
size_t attrsize = 0;
void *attrdata;
int n_attr = 0;
state = avl_find_element(&u->user_state, id, state, node);
if (state)
return &state->data;
blobmsg_parse(policy, __USER_ATTR_MAX, tb, blobmsg_data(data), blobmsg_len(data));
if ((cur = tb[USER_ATTR_SALT]) != NULL)
salt_len = strlen(blobmsg_get_string(cur)) / 2;
if ((cur = tb[USER_ATTR_HASH]) != NULL)
pw_len = strlen(blobmsg_get_string(cur)) / 2;
else if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
pw_len = blobmsg_len(cur) - 1;
radius_count_attrs(tb, &n_attr, &attrsize);
state = calloc_a(sizeof(*state), &name_buf, strlen(id) + 1,
&password_buf, pw_len,
&salt_buf, salt_len,
&astate.attr, n_attr * sizeof(*astate.attr),
&astate.buf, n_attr * sizeof(*astate.buf),
&astate.attrdata, attrsize);
eap = &state->data;
eap->salt = salt_len ? salt_buf : NULL;
eap->salt_len = salt_len;
eap->password = pw_len ? password_buf : NULL;
eap->password_len = pw_len;
eap->force_version = -1;
if ((cur = tb[USER_ATTR_SALT]) != NULL)
hexstr2bin(blobmsg_get_string(cur), salt_buf, salt_len);
if ((cur = tb[USER_ATTR_PASSWORD]) != NULL)
memcpy(password_buf, blobmsg_get_string(cur), pw_len);
else if ((cur = tb[USER_ATTR_HASH]) != NULL) {
hexstr2bin(blobmsg_get_string(cur), password_buf, pw_len);
eap->password_hash = 1;
}
radius_user_parse_methods(eap, tb[USER_ATTR_METHODS]);
if (n_attr > 0) {
cur = tb[USER_ATTR_RADIUS];
eap->accept_attr = astate.attr;
radius_parse_attrs(tb, &astate);
}
state->node.key = strcpy(name_buf, id);
avl_insert(&u->user_state, &state->node);
return &state->data;
free:
free(state);
return NULL;
}
static int radius_get_eap_user(void *ctx, const u8 *identity,
size_t identity_len, int phase2,
struct eap_user *user)
{
struct radius_state *s = ctx;
struct radius_user_data *u = phase2 ? &s->phase2 : &s->phase1;
struct blob_attr *entry;
struct eap_user *data;
char *id;
if (identity_len > 512)
return -1;
load_userfile(s);
id = alloca(identity_len + 1);
memcpy(id, identity, identity_len);
id[identity_len] = 0;
entry = radius_user_get(u, id);
if (!entry)
return -1;
if (!user)
return 0;
data = radius_user_get_state(u, entry, id);
if (!data)
return -1;
*user = *data;
if (user->password_len > 0)
user->password = os_memdup(user->password, user->password_len);
if (user->salt_len > 0)
user->salt = os_memdup(user->salt, user->salt_len);
user->phase2 = phase2;
return 0;
}
static int radius_setup(struct radius_state *s, struct radius_config *c)
{
struct eap_config *eap = &s->eap;
struct tls_config conf = {
.event_cb = radius_tls_event,
.tls_flags = TLS_CONN_DISABLE_TLSv1_3,
.cb_ctx = s,
};
eap->eap_server = 1;
eap->max_auth_rounds = 100;
eap->max_auth_rounds_short = 50;
eap->ssl_ctx = tls_init(&conf);
if (!eap->ssl_ctx) {
wpa_printf(MSG_INFO, "TLS init failed\n");
return 1;
}
if (tls_global_set_params(eap->ssl_ctx, &c->tls)) {
wpa_printf(MSG_INFO, "failed to set TLS parameters\n");
return 1;
}
c->radius.eap_cfg = eap;
c->radius.conf_ctx = s;
c->radius.get_eap_user = radius_get_eap_user;
s->radius = radius_server_init(&c->radius);
if (!s->radius) {
wpa_printf(MSG_INFO, "failed to initialize radius server\n");
return 1;
}
return 0;
}
static int radius_init(struct radius_state *s)
{
memset(s, 0, sizeof(*s));
radius_userdata_init(&s->phase1);
radius_userdata_init(&s->phase2);
}
static void radius_deinit(struct radius_state *s)
{
if (s->radius)
radius_server_deinit(s->radius);
if (s->eap.ssl_ctx)
tls_deinit(s->eap.ssl_ctx);
radius_userdata_free(&s->phase1);
radius_userdata_free(&s->phase2);
}
static int usage(const char *progname)
{
fprintf(stderr, "Usage: %s <options>\n",
progname);
}
int radius_main(int argc, char **argv)
{
static struct radius_state state = {};
static struct radius_config config = {};
const char *progname = argv[0];
int ret = 0;
int ch;
wpa_debug_setup_stdout();
wpa_debug_level = 0;
if (eloop_init()) {
wpa_printf(MSG_ERROR, "Failed to initialize event loop");
return 1;
}
eap_server_register_methods();
radius_init(&state);
while ((ch = getopt(argc, argv, "6C:c:d:i:k:K:p:P:s:u:")) != -1) {
switch (ch) {
case '6':
config.radius.ipv6 = 1;
break;
case 'C':
config.tls.ca_cert = optarg;
break;
case 'c':
if (config.tls.client_cert2)
return usage(progname);
if (config.tls.client_cert)
config.tls.client_cert2 = optarg;
else
config.tls.client_cert = optarg;
break;
case 'd':
config.tls.dh_file = optarg;
break;
case 'i':
state.eap.server_id = optarg;
state.eap.server_id_len = strlen(optarg);
break;
case 'k':
if (config.tls.private_key2)
return usage(progname);
if (config.tls.private_key)
config.tls.private_key2 = optarg;
else
config.tls.private_key = optarg;
break;
case 'K':
if (config.tls.private_key_passwd2)
return usage(progname);
if (config.tls.private_key_passwd)
config.tls.private_key_passwd2 = optarg;
else
config.tls.private_key_passwd = optarg;
break;
case 'p':
config.radius.auth_port = atoi(optarg);
break;
case 'P':
config.radius.acct_port = atoi(optarg);
break;
case 's':
config.radius.client_file = optarg;
break;
case 'u':
state.user_file = optarg;
break;
default:
return usage(progname);
}
}
if (!config.tls.client_cert || !config.tls.private_key ||
!config.radius.client_file || !state.eap.server_id ||
!state.user_file) {
wpa_printf(MSG_INFO, "missing options\n");
goto out;
}
ret = radius_setup(&state, &config);
if (ret)
goto out;
load_userfile(&state);
eloop_run();
out:
radius_deinit(&state);
os_program_deinit();
return ret;
}

2039
src/ap/ubus.c Normal file

File diff suppressed because it is too large Load diff

166
src/ap/ubus.h Normal file
View file

@ -0,0 +1,166 @@
/*
* hostapd / ubus support
* Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef __HOSTAPD_UBUS_H
#define __HOSTAPD_UBUS_H
enum hostapd_ubus_event_type {
HOSTAPD_UBUS_PROBE_REQ,
HOSTAPD_UBUS_AUTH_REQ,
HOSTAPD_UBUS_ASSOC_REQ,
HOSTAPD_UBUS_TYPE_MAX
};
struct hostapd_ubus_request {
enum hostapd_ubus_event_type type;
const struct ieee80211_mgmt *mgmt_frame;
const struct ieee802_11_elems *elems;
int ssi_signal; /* dBm */
const u8 *addr;
};
struct hostapd_iface;
struct hostapd_data;
struct hapd_interfaces;
struct rrm_measurement_beacon_report;
struct sta_info;
#ifdef UBUS_SUPPORT
#include <libubox/avl.h>
#include <libubus.h>
struct hostapd_ubus_bss {
struct ubus_object obj;
struct avl_tree banned;
int notify_response;
};
void hostapd_ubus_add_iface(struct hostapd_iface *iface);
void hostapd_ubus_free_iface(struct hostapd_iface *iface);
void hostapd_ubus_add_bss(struct hostapd_data *hapd);
void hostapd_ubus_free_bss(struct hostapd_data *hapd);
void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req);
void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len);
void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac);
void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
const u8 *addr, u8 token, u8 rep_mode,
struct rrm_measurement_beacon_report *rep,
size_t len);
void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
int chan_width, int cf1, int cf2);
void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_add(struct hapd_interfaces *interfaces);
void hostapd_ubus_free(struct hapd_interfaces *interfaces);
int hostapd_ubus_notify_bss_transition_query(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
const u8 *candidate_list, u16 candidate_list_len);
void hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
const char *auth_alg);
void hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq);
#ifdef CONFIG_APUP
void hostapd_ubus_notify_apup_newpeer(
struct hostapd_data *hapd, const u8 *addr, const char *ifname);
#endif // def CONFIG_APUP
#else
struct hostapd_ubus_bss {};
static inline void hostapd_ubus_add_iface(struct hostapd_iface *iface)
{
}
static inline void hostapd_ubus_free_iface(struct hostapd_iface *iface)
{
}
static inline void hostapd_ubus_add_bss(struct hostapd_data *hapd)
{
}
static inline void hostapd_ubus_free_bss(struct hostapd_data *hapd)
{
}
static inline void hostapd_ubus_add_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
}
static inline void hostapd_ubus_remove_vlan(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
}
static inline int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req)
{
return 0;
}
static inline void hostapd_ubus_handle_link_measurement(struct hostapd_data *hapd, const u8 *data, size_t len)
{
}
static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac)
{
}
static inline void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd,
const u8 *addr, u8 token,
u8 rep_mode,
struct rrm_measurement_beacon_report *rep,
size_t len)
{
}
static inline void hostapd_ubus_notify_radar_detected(struct hostapd_iface *iface, int frequency,
int chan_width, int cf1, int cf2)
{
}
static inline void hostapd_ubus_notify_bss_transition_response(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 status_code,
u8 bss_termination_delay, const u8 *target_bssid,
const u8 *candidate_list, u16 candidate_list_len)
{
}
static inline void hostapd_ubus_add(struct hapd_interfaces *interfaces)
{
}
static inline void hostapd_ubus_free(struct hapd_interfaces *interfaces)
{
}
static inline int hostapd_ubus_notify_bss_transition_query(
struct hostapd_data *hapd, const u8 *addr, u8 dialog_token, u8 reason,
const u8 *candidate_list, u16 candidate_list_len)
{
return 0;
}
static inline void
hostapd_ubus_notify_authorized(struct hostapd_data *hapd, struct sta_info *sta,
const char *auth_alg)
{
}
static inline void
hostapd_ubus_notify_csa(struct hostapd_data *hapd, int freq)
{
}
#endif
#endif

View file

@ -0,0 +1,69 @@
#ifndef BUILD_FEATURES_H
#define BUILD_FEATURES_H
static inline int has_feature(const char *feat)
{
#if defined(IEEE8021X_EAPOL) || (defined(HOSTAPD) && !defined(CONFIG_NO_RADIUS))
if (!strcmp(feat, "eap"))
return 1;
#endif
#ifdef CONFIG_IEEE80211AC
if (!strcmp(feat, "11ac"))
return 1;
#endif
#ifdef CONFIG_IEEE80211AX
if (!strcmp(feat, "11ax"))
return 1;
#endif
#ifdef CONFIG_IEEE80211BE
if (!strcmp(feat, "11be"))
return 1;
#endif
#ifdef CONFIG_IEEE80211R
if (!strcmp(feat, "11r"))
return 1;
#endif
#ifdef CONFIG_ACS
if (!strcmp(feat, "acs"))
return 1;
#endif
#ifdef CONFIG_SAE
if (!strcmp(feat, "sae"))
return 1;
#endif
#ifdef CONFIG_OWE
if (!strcmp(feat, "owe"))
return 1;
#endif
#ifdef CONFIG_SUITEB192
if (!strcmp(feat, "suiteb192"))
return 1;
#endif
#ifdef CONFIG_WEP
if (!strcmp(feat, "wep"))
return 1;
#endif
#ifdef CONFIG_HS20
if (!strcmp(feat, "hs20"))
return 1;
#endif
#ifdef CONFIG_WPS
if (!strcmp(feat, "wps"))
return 1;
#endif
#ifdef CONFIG_FILS
if (!strcmp(feat, "fils"))
return 1;
#endif
#ifdef CONFIG_OCV
if (!strcmp(feat, "ocv"))
return 1;
#endif
#ifdef CONFIG_MESH
if (!strcmp(feat, "mesh"))
return 1;
#endif
return 0;
}
#endif /* BUILD_FEATURES_H */

280
wpa_supplicant/ubus.c Normal file
View file

@ -0,0 +1,280 @@
/*
* wpa_supplicant / ubus support
* Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
* Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/wpabuf.h"
#include "common/ieee802_11_defs.h"
#include "wpa_supplicant_i.h"
#include "wps_supplicant.h"
#include "ubus.h"
static struct ubus_context *ctx;
static struct blob_buf b;
static int ctx_ref;
static inline struct wpa_global *get_wpa_global_from_object(struct ubus_object *obj)
{
return container_of(obj, struct wpa_global, ubus_global);
}
static inline struct wpa_supplicant *get_wpas_from_object(struct ubus_object *obj)
{
return container_of(obj, struct wpa_supplicant, ubus.obj);
}
static void ubus_reconnect_timeout(void *eloop_data, void *user_ctx)
{
if (ubus_reconnect(ctx, NULL)) {
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
return;
}
ubus_add_uloop(ctx);
}
static void wpas_ubus_connection_lost(struct ubus_context *ctx)
{
uloop_fd_delete(&ctx->sock);
eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL);
}
static bool wpas_ubus_init(void)
{
if (ctx)
return true;
eloop_add_uloop();
ctx = ubus_connect(NULL);
if (!ctx)
return false;
ctx->connection_lost = wpas_ubus_connection_lost;
ubus_add_uloop(ctx);
return true;
}
static void wpas_ubus_ref_inc(void)
{
ctx_ref++;
}
static void wpas_ubus_ref_dec(void)
{
ctx_ref--;
if (!ctx)
return;
if (ctx_ref)
return;
uloop_fd_delete(&ctx->sock);
ubus_free(ctx);
ctx = NULL;
}
static int
wpas_bss_get_features(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
blob_buf_init(&b, 0);
blobmsg_add_u8(&b, "ht_supported", ht_supported(wpa_s->hw.modes));
blobmsg_add_u8(&b, "vht_supported", vht_supported(wpa_s->hw.modes));
ubus_send_reply(ctx, req, b.head);
return 0;
}
static int
wpas_bss_reload(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
if (wpa_supplicant_reload_configuration(wpa_s))
return UBUS_STATUS_UNKNOWN_ERROR;
else
return 0;
}
#ifdef CONFIG_WPS
enum {
WPS_START_MULTI_AP,
__WPS_START_MAX
};
static const struct blobmsg_policy wps_start_policy[] = {
[WPS_START_MULTI_AP] = { "multi_ap", BLOBMSG_TYPE_BOOL },
};
static int
wpas_bss_wps_start(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int rc;
struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
struct blob_attr *tb[__WPS_START_MAX], *cur;
int multi_ap = 0;
blobmsg_parse(wps_start_policy, __WPS_START_MAX, tb, blobmsg_data(msg), blobmsg_data_len(msg));
if (tb[WPS_START_MULTI_AP])
multi_ap = blobmsg_get_bool(tb[WPS_START_MULTI_AP]);
rc = wpas_wps_start_pbc(wpa_s, NULL, 0, multi_ap);
if (rc != 0)
return UBUS_STATUS_NOT_SUPPORTED;
return 0;
}
static int
wpas_bss_wps_cancel(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
int rc;
struct wpa_supplicant *wpa_s = get_wpas_from_object(obj);
rc = wpas_wps_cancel(wpa_s);
if (rc != 0)
return UBUS_STATUS_NOT_SUPPORTED;
return 0;
}
#endif
static const struct ubus_method bss_methods[] = {
UBUS_METHOD_NOARG("reload", wpas_bss_reload),
UBUS_METHOD_NOARG("get_features", wpas_bss_get_features),
#ifdef CONFIG_WPS
UBUS_METHOD_NOARG("wps_start", wpas_bss_wps_start),
UBUS_METHOD_NOARG("wps_cancel", wpas_bss_wps_cancel),
#endif
};
static struct ubus_object_type bss_object_type =
UBUS_OBJECT_TYPE("wpas_bss", bss_methods);
void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
{
struct ubus_object *obj = &wpa_s->ubus.obj;
char *name;
int ret;
if (!wpas_ubus_init())
return;
if (asprintf(&name, "wpa_supplicant.%s", wpa_s->ifname) < 0)
return;
obj->name = name;
obj->type = &bss_object_type;
obj->methods = bss_object_type.methods;
obj->n_methods = bss_object_type.n_methods;
ret = ubus_add_object(ctx, obj);
wpas_ubus_ref_inc();
}
void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
{
struct ubus_object *obj = &wpa_s->ubus.obj;
char *name = (char *) obj->name;
if (!ctx)
return;
if (obj->id) {
ubus_remove_object(ctx, obj);
wpas_ubus_ref_dec();
}
free(name);
}
#ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred)
{
u16 auth_type;
char *ifname, *encryption, *ssid, *key;
size_t ifname_len;
if (!cred)
return;
auth_type = cred->auth_type;
if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))
auth_type = WPS_AUTH_WPA2PSK;
if (auth_type != WPS_AUTH_OPEN &&
auth_type != WPS_AUTH_WPAPSK &&
auth_type != WPS_AUTH_WPA2PSK) {
wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
"unsupported authentication type 0x%x",
auth_type);
return;
}
if (auth_type == WPS_AUTH_WPAPSK || auth_type == WPS_AUTH_WPA2PSK) {
if (cred->key_len < 8 || cred->key_len > 2 * PMK_LEN) {
wpa_printf(MSG_ERROR, "WPS: Reject PSK credential with "
"invalid Network Key length %lu",
(unsigned long) cred->key_len);
return;
}
}
blob_buf_init(&b, 0);
ifname_len = strlen(wpa_s->ifname);
ifname = blobmsg_alloc_string_buffer(&b, "ifname", ifname_len + 1);
memcpy(ifname, wpa_s->ifname, ifname_len + 1);
ifname[ifname_len] = '\0';
blobmsg_add_string_buffer(&b);
switch (auth_type) {
case WPS_AUTH_WPA2PSK:
encryption = "psk2";
break;
case WPS_AUTH_WPAPSK:
encryption = "psk";
break;
default:
encryption = "none";
break;
}
blobmsg_add_string(&b, "encryption", encryption);
ssid = blobmsg_alloc_string_buffer(&b, "ssid", cred->ssid_len + 1);
memcpy(ssid, cred->ssid, cred->ssid_len);
ssid[cred->ssid_len] = '\0';
blobmsg_add_string_buffer(&b);
if (cred->key_len > 0) {
key = blobmsg_alloc_string_buffer(&b, "key", cred->key_len + 1);
memcpy(key, cred->key, cred->key_len);
key[cred->key_len] = '\0';
blobmsg_add_string_buffer(&b);
}
// ubus_notify(ctx, &wpa_s->ubus.obj, "wps_credentials", b.head, -1);
ubus_send_event(ctx, "wps_credentials", b.head);
}
#endif /* CONFIG_WPS */

55
wpa_supplicant/ubus.h Normal file
View file

@ -0,0 +1,55 @@
/*
* wpa_supplicant / ubus support
* Copyright (c) 2018, Daniel Golle <daniel@makrotopia.org>
* Copyright (c) 2013, Felix Fietkau <nbd@nbd.name>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#ifndef __WPAS_UBUS_H
#define __WPAS_UBUS_H
struct wpa_supplicant;
struct wpa_global;
#include "wps_supplicant.h"
#ifdef UBUS_SUPPORT
#include <libubus.h>
struct wpas_ubus_bss {
struct ubus_object obj;
};
void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s);
void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s);
#ifdef CONFIG_WPS
void wpas_ubus_notify(struct wpa_supplicant *wpa_s, const struct wps_credential *cred);
#endif
#else
struct wpas_ubus_bss {};
static inline void wpas_ubus_add_bss(struct wpa_supplicant *wpa_s)
{
}
static inline void wpas_ubus_free_bss(struct wpa_supplicant *wpa_s)
{
}
static inline void wpas_ubus_notify(struct wpa_supplicant *wpa_s, struct wps_credential *cred)
{
}
static inline void wpas_ubus_add(struct wpa_global *global)
{
}
static inline void wpas_ubus_free(struct wpa_global *global)
{
}
#endif
#endif