-
Jakob Olsson authoredJakob Olsson authored
config.c 61.24 KiB
/*
* config.c - configurations handling
*
* Copyright (C) 2019 IOPSYS Software Solutions AB. All rights reserved.
*
* Author: anjan.chanda@iopsys.eu
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef IFNAMSIZ
#define IFNAMSIZ 16
#endif
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
//Security and encryption
#define WPS_AUTH_OPEN (0x0001)
#define WPS_AUTH_WPAPSK (0x0002)
#define WPS_AUTH_SHARED (0x0004) /* deprecated */
#define WPS_AUTH_WPA (0x0008)
#define WPS_AUTH_WPA2 (0x0010)
#define WPS_AUTH_WPA2PSK (0x0020)
#define ATTR_ENCR_TYPE_FLAGS (0x1010)
#define WPS_ENCR_NONE (0x0001)
#define WPS_ENCR_WEP (0x0002) /* deprecated */
#define WPS_ENCR_TKIP (0x0004)
#define WPS_ENCR_AES (0x0008)
#include <json-c/json.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 <i1905_wsc.h>
#include <1905_tlvs.h>
#include <map22.h>
#include <easy/easy.h>
#include <map_module22.h>
#include <bufutil.h>
#include <easy/easy.h>
#include "debug.h"
#include "utils.h"
#include "steer_rules.h"
#include "comm.h"
#include "msgqueue.h"
#include "worker.h"
#include "config.h"
#include "agent.h"
// UCI sections
#define UCI_BK_AGENT "bk-iface"
#define UCI_FH_AGENT "fh-iface"
#define UCI_WLAN_IFACE "wifi-iface"
#define UCI_WL_DEVICE "wifi-device"
#define UCI_WIRELESS "wireless"
#define UCI_IEEE1905 "ieee1905"
#define UCI_AGENT "mapagent"
int verbose;
char *replace_char(char *str, char find, char replace)
{
char *current_pos = strchr(str, find);
while (current_pos) {
*current_pos = replace;
current_pos = strchr(current_pos, find);
}
return str;
}
int set_value(struct uci_context *ctx, struct uci_package *pkg,
struct uci_section *section, const char *key,
const char *value, enum uci_option_type type)
{
struct uci_ptr ptr = {0};
ptr.p = pkg;
ptr.s = section;
ptr.option = key;
ptr.value = value;
if (type == UCI_TYPE_STRING)
return uci_set(ctx, &ptr);
if (type == UCI_TYPE_LIST)
return uci_add_list(ctx, &ptr);
return -1;
}
int set_value_by_string(const char *package, const char *section,
const char *key, const char *value, enum uci_option_type type)
{
struct uci_ptr ptr = {0};
struct uci_context *ctx;
int rv;
ctx = uci_alloc_context();
if (!ctx)
return -1;
ptr.package = package;
ptr.section = section;
ptr.option = key;
ptr.value = value;
if (type == UCI_TYPE_STRING)
rv = uci_set(ctx, &ptr);
if (type == UCI_TYPE_LIST)
rv = uci_add_list(ctx, &ptr);
uci_commit(ctx, &ptr.p, false);
uci_free_context(ctx);
return rv;
}
struct uci_section *config_get_section(struct uci_context *ctx,
struct uci_package *pkg, const char *type, const char *key,
const char *value)
{
struct uci_element *e;
struct uci_section *section;
/* get the wet iface section */
uci_foreach_element(&pkg->sections, e) {
const char *c_value;
section = uci_to_section(e);
if (strcmp(section->type, type))
continue;
c_value = uci_lookup_option_string(ctx, section, key);
if (c_value && !strcmp(c_value, value))
return section;
}
return NULL;
}
struct uci_package *uci_load_pkg(struct uci_context **ctx, const char *config)
{
struct uci_package *pkg;
if (!*ctx) {
*ctx = uci_alloc_context();
if (!*ctx)
return NULL;
}
if (uci_load(*ctx, config, &pkg) != UCI_OK) {
free(*ctx);
return NULL;
}
return pkg;
}
/* TODO: causes segfault in disc? */
char *uci_get_bridge(char *ifname, char *bridge)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
strncpy(bridge, "lan", 15);
return bridge;
pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
if (!pkg)
return NULL;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
struct uci_option *opt;
if (strcmp(s->type, UCI_WLAN_IFACE))
continue;
opt = uci_lookup_option(ctx, s, "ifname");
if (!opt || opt->type != UCI_TYPE_STRING)
continue;
if (!strncmp(opt->v.string, ifname, 16))
continue;
opt = uci_lookup_option(ctx, s, "network");
if (!opt || opt->type != UCI_TYPE_STRING)
continue;
strncpy(bridge, opt->v.string, 16);
break;
}
uci_unload(ctx, pkg);
uci_free_context(ctx);
return bridge;
}
int wifi_get_iface_bssid(char *ifname, uint8_t *bssid)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_section *section;
struct uci_ptr ptr = {0};
int ret = -1;
if (!bssid)
return ret;
pkg = uci_load_pkg(&ctx, "wireless");
if (!pkg)
return ret;
section = config_get_section(ctx, pkg, "wifi-iface", "ifname", ifname);
if (!section)
goto out_pkg;
ptr.p = pkg;
ptr.s = section;
ptr.option = "bssid";
ptr.target = UCI_TYPE_OPTION;
ret = uci_lookup_ptr(ctx, &ptr, NULL, false);
if (!ret && ptr.o)
hwaddr_aton(ptr.o->v.string, bssid);
else
memset(bssid, 0, 6);
out_pkg:
uci_unload(ctx, pkg);
uci_free_context(ctx);
return ret;
}
/* TODO: can it be generalized? */
int wifi_set_iface_bssid(struct netif_bk *bk, uint8_t *bssid)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_section *section;
char bssid_str[18] = {0};
int ret = -1;
pkg = uci_load_pkg(&ctx, "wireless");
if (!pkg)
return ret;
section = config_get_section(ctx, pkg, "wifi-iface", "ifname", bk->name);
if (!section)
goto out_pkg;
if (bssid && !hwaddr_is_zero(bssid))
hwaddr_ntoa(bssid, bssid_str);
dbg("|%s:%d| setting bssid to %s\n", bssid_str);
ret = set_value(ctx, pkg, section, "bssid", bssid_str, UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
uci_reload_services("wireless");
out_pkg:
uci_unload(ctx, pkg);
uci_free_context(ctx);
return ret;
}
int config_del_iface(const char *config, const char *type, const char *ifname)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_section *section;
struct uci_ptr ptr = {0};
int rv = -1;
ctx = uci_alloc_context();
if (!ctx)
goto out;
if (uci_load(ctx, config, &pkg) != UCI_OK) {
dbg("config file 'wireless' not found!\n");
goto out_uci;
}
section = config_get_section(ctx, pkg, type, "ifname", ifname);
if (!section)
goto out_pkg;
ptr.p = pkg;
ptr.s = section;
uci_delete(ctx, &ptr);
uci_commit(ctx, &pkg, false);
out_pkg:
uci_unload(ctx, pkg);
out_uci:
uci_free_context(ctx);
out:
return rv;
}
int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
const char *ssid, const char *key)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_section *section;
int rv = -1;
ctx = uci_alloc_context();
if (!ctx)
goto out;
if (uci_load(ctx, "wireless", &pkg) != UCI_OK) {
dbg("config file 'wireless' not found!\n");
goto out_uci;
}
section = config_get_section(ctx, pkg, "wifi-iface", "ifname", ifname);
if (!section)
goto out_pkg;
set_value(ctx, pkg, section, "encryption", encryption, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "ssid", ssid, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "key", key, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "wds", "1", UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
out_pkg:
uci_unload(ctx, pkg);
out_uci:
uci_free_context(ctx);
out:
return rv;
}
char *agent_config_get_ethwan(char *ifname)
{
struct uci_context *ctx;
struct uci_ptr ptr = {0};
ctx = uci_alloc_context();
if (!ctx)
return NULL;
//ptr.value = value;
ptr.package = "ports";
ptr.section = "WAN";
ptr.option = "ifname";
ptr.target = UCI_TYPE_OPTION;
if (uci_lookup_ptr(ctx, &ptr, NULL, false)) {
uci_free_context(ctx);
return NULL;
}
strncpy(ifname, ptr.o->v.string, 15);
uci_free_context(ctx);
return ifname;
}
struct uci_section *config_add_section(struct uci_context *ctx,
struct uci_package *pkg, const char *config, const char *type,
const char *key, const char *value)
{
struct uci_section *section = NULL;
struct uci_ptr ptr = {0};
int rv = -1;
section = config_get_section(ctx, pkg, type, key, value);
if (!section) {
rv = uci_add_section(ctx, pkg, type, §ion);
if (rv)
goto out_pkg;
rv = uci_save(ctx, pkg);
if (rv)
goto out_pkg;
}
ptr.value = value;
ptr.package = config;
ptr.section = section->e.name;
ptr.option = key;
ptr.target = UCI_TYPE_OPTION;
uci_lookup_ptr(ctx, &ptr, NULL, false);
uci_set(ctx, &ptr);
uci_save(ctx, ptr.p);
out_pkg:
return section;
}
int config_add_default_wifi_iface(const char *config, const char *type,
const char *ifname, const char *device, const char *network,
const char *mode)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_section *section;
int rv = -1;
ctx = uci_alloc_context();
if (!ctx)
goto out;
if (uci_load(ctx, config, &pkg) != UCI_OK) {
dbg("config file 'wireless' not found!\n");
goto out_uci;
}
section = config_add_section(ctx, pkg, config, type, "ifname", ifname);
if (!section)
return -1;
set_value(ctx, pkg, section, "device", device, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "network", network, UCI_TYPE_STRING);
//set_value(ctx, pkg, section, "mode", mode, UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
out_pkg:
uci_unload(ctx, pkg);
out_uci:
uci_free_context(ctx);
out:
return 0;
}
int config_add_default_agent_iface(const char *config, const char *type,
const char *ifname, enum wifi_band band)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_section *section;
int rv = -1;
ctx = uci_alloc_context();
if (!ctx)
goto out;
if (uci_load(ctx, config, &pkg) != UCI_OK) {
dbg("config file 'wireless' not found!\n");
goto out_uci;
}
section = config_add_section(ctx, pkg, config, type, "ifname", ifname);
if (!section)
return -1;
trace("band = %d\n", band);
if (band == BAND_5)
set_value(ctx, pkg, section, "band", "5", UCI_TYPE_STRING);
if (band == BAND_2)
set_value(ctx, pkg, section, "band", "2", UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
out_pkg:
uci_unload(ctx, pkg);
out_uci:
uci_free_context(ctx);
out:
return 0;
}
/* below functions are mostly taken from ieee1905d */
bool uci_check_wifi_iface(char *package_name, char *ifname,
char *section)
{
bool ret;
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
if (!package_name || !ifname)
return false;
ctx = uci_alloc_context();
if (!ctx)
return false;
if (uci_load(ctx, package_name, &pkg)) {
uci_free_context(ctx);
return false;
}
ret = false;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, section)) {
struct uci_option *opt = uci_lookup_option(ctx, s,
"ifname");
if (!opt || opt->type != UCI_TYPE_STRING)
continue;
if (strcmp(opt->v.string, ifname) == 0) {
ret = true;
break;
}
}
}
uci_unload(ctx, pkg);
uci_free_context(ctx);
return ret;
}
bool uci_set_wireless_interface_option(char *package_name,
char *section_type, char *search_key, char *search_val,
char *option, char *value)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
if (!package_name || !search_val || !option || !value)
return false;
ctx = uci_alloc_context();
if (!ctx)
return false;
if (uci_load(ctx, package_name, &pkg)) {
uci_free_context(ctx);
return false;
}
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, section_type)) {
struct uci_option *opt = uci_lookup_option(ctx, s,
search_key);
if (!opt || opt->type != UCI_TYPE_STRING)
continue;
if (strcmp(opt->v.string, search_val) == 0) {
struct uci_ptr ptr = {0};
ptr.value = value;
ptr.package = package_name;
ptr.section = s->e.name;
ptr.option = option;
ptr.target = UCI_TYPE_OPTION;
if (uci_lookup_ptr(ctx, &ptr, NULL, false) ||
!UCI_LOOKUP_COMPLETE)
break;
if (uci_set(ctx, &ptr) == UCI_OK)
uci_save(ctx, ptr.p);
break;
}
}
}
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
uci_free_context(ctx);
return false;
}
static bool get_encryption_value(uint16_t auth_type, uint16_t encryption_type,
char *encrypt_val, size_t elen)
{
if (!encrypt_val)
return false;
if ((auth_type & WPS_AUTH_WPAPSK) && (auth_type & WPS_AUTH_WPA2PSK))
strncat(encrypt_val, "psk-mixed", elen);
else if ((auth_type & WPS_AUTH_WPA) && (auth_type & WPS_AUTH_WPA2))
strncat(encrypt_val, "wpa-mixed", elen);
else if (auth_type & WPS_AUTH_WPAPSK)
strncat(encrypt_val, "psk", elen);
else if (auth_type & WPS_AUTH_WPA2PSK)
strncat(encrypt_val, "psk2", elen);
else if (auth_type & WPS_AUTH_WPA)
strncat(encrypt_val, "wpa", elen);
else if (auth_type & WPS_AUTH_WPA2)
strncat(encrypt_val, "wpa2", elen);
else if (auth_type & WPS_AUTH_OPEN)
strncat(encrypt_val, "none", elen);
else
return false;
//Check for the encryption type
if ((encryption_type & WPS_ENCR_TKIP) &&
(encryption_type & WPS_ENCR_AES))
strncat(encrypt_val, "+tkip+aes", elen);
else if (encryption_type & WPS_ENCR_TKIP)
strncat(encrypt_val, "+tkip", elen);
else if (encryption_type & WPS_ENCR_AES)
strncat(encrypt_val, "+aes", elen);
return true;
}
bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
char *section_type, char *section_name)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_section *s;
struct uci_ptr ptr = {0};
bool ret = false;
if (!interface_name || !package_name)
return false;
ctx = uci_alloc_context();
if (!ctx)
return false;
if (uci_load(ctx, package_name, &pkg))
goto out_ctx;
ptr.p = pkg;
if (section_name) {
ptr.section = section_name;
ptr.value = section_type;
ptr.option = NULL;
uci_set(ctx, &ptr);
if (uci_save(ctx, ptr.p) != UCI_OK)
goto out_unload;
} else {
if (uci_add_section(ctx, pkg, section_type, &s) != UCI_OK)
goto out_unload;
if (uci_save(ctx, pkg) != UCI_OK)
goto out_unload;
ptr.section = s->e.name;
}
ptr.value = interface_name;
ptr.option = "ifname";
ptr.target = UCI_TYPE_OPTION;
uci_lookup_ptr(ctx, &ptr, NULL, false);
uci_set(ctx, &ptr);
uci_save(ctx, ptr.p);
uci_commit(ctx, &pkg, false);
ret = true;
out_unload:
uci_unload(ctx, pkg);
out_ctx:
uci_free_context(ctx);
return ret;
}
static int ubus_call(const char *object, const char *method,
struct blob_buf *data, void *callback, void *cb_arg)
{
uint32_t id;
struct ubus_context *ctx = ubus_connect(NULL);
if (!ctx) {
err("ubus_connect failed\n");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (ubus_lookup_id(ctx, object, &id)) {
err("(%s) not present\n", object);
ubus_free(ctx);
return UBUS_STATUS_UNKNOWN_ERROR;
}
// Invoke Ubus to get data from uspd
if (ubus_invoke(ctx, id, method, data->head, callback, cb_arg, 1000)) {
err("ubus call failed\n");
ubus_free(ctx);
return UBUS_STATUS_UNKNOWN_ERROR;
}
ubus_free(ctx);
return UBUS_STATUS_OK;
}
bool uci_reload_services(char *services)
{
struct blob_buf bb;
int rv = 0;
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
blobmsg_add_string(&bb, "config", services);
rv = ubus_call("uci", "commit", &bb, NULL, NULL);
info("## Reloading uci config %d\n", rv);
//if (!ubus_call("uci", "reload_config", &bb, NULL, NULL))
// return true;
//ubus_call("uci", "reload_config", &bb, NULL, NULL);
blob_buf_free(&bb);
return false;
}
#if 0 /* Deprecated for 6.1 - Possibly bring back in 6.2 with modifications */
/* TODO: introduce option and vendor extension to make this logic redundant */
int uci_apply_wps_credentials(struct agent_config *cfg, enum wifi_band band)
{
struct netif_bkcfg *bk;
struct netif_fhcfg *fh;
list_for_each_entry(bk, &cfg->bklist, list) {
if (bk->band != band)
continue;
list_for_each_entry(fh, &cfg->fhlist, list) {
if (fh->band != band)
continue;
dbg("Applying bBSS credentials to %s:\n", fh->name);
dbg(" - SSID : %s\n", bk->ssid);
dbg(" - NETWORK_KEY : %s\n", bk->key);
uci_set_wireless_interface_option(UCI_WIRELESS,
UCI_WLAN_IFACE,
"ifname",
fh->name,
"multi_ap_backhaul_ssid",
bk->ssid);
uci_set_wireless_interface_option(UCI_WIRELESS,
UCI_WLAN_IFACE,
"ifname",
fh->name,
"multi_ap_backhaul_key",
bk->key);
uci_set_wireless_interface_option(UCI_WIRELESS,
UCI_WLAN_IFACE, "ifname", fh->name, "wps", "1");
uci_set_wireless_interface_option(UCI_WIRELESS,
UCI_WLAN_IFACE, "ifname", fh->name,
"wps_pushbutton", "1");
}
break;
}
return 0;
}
#endif
/*
* Will only be successful if uci_apply_m2 is done prior, or interfaces already
* exist and are configured through other means
*/
void uci_apply_traffic_sep(struct tlv_traffic_sep_policy *tlv)
{
int i;
uint8_t *ptr;
ptr = tlv;
ptr++;
for (i = 0; i < tlv->num_ssid; i++) {
char ssid[33] = {0};
char vid[8] = {0};
uint8_t len = 0;
len = *ptr;
ptr++;
memcpy(ssid, ptr, len);
ptr += len;
snprintf(vid, sizeof(vid), "%u", buf_get_be16(ptr));
ptr += 2;
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT,
"ssid", ssid, "vid", vid);
}
}
/* TODO: batch the changes arther than commit oneby one */
int uci_apply_m2(struct agent_config *cfg, char *interface_name, char *device,
struct wps_credential *out, bool onboarded, struct iop_ext *exts)
{
bool ret;
char auth_type_str[20] = {0};
char multiap_str[2] = {0};
uint8_t multi_ap = 0;
char band_str[2] = {0};
char ipaddr_str[INET_ADDRSTRLEN] = {0};
char ssid[33] = {0}, network_key[65] = {0}, bridge_buf[16] = {0}, *bridge;
/* step past br- prefix if present*/
bridge = bridge_buf;
if (!strncmp("br-", bridge, 3))
bridge += 3;
dbg("%s %d band = %d\n", __func__, __LINE__, out->band);
if (out->band == BAND_5)
strncpy(band_str, "5", 1);
else if (out->band == BAND_2)
strncpy(band_str, "2", 1);
else /* TODO: 60 */
return M2_PROCESS_ERROR;
memcpy(ssid, out->ssid, out->ssidlen);
memcpy(network_key, out->key, out->keylen);
memcpy(bridge, exts->bridge, 15);
inet_ntop(AF_INET, &exts->br_ip, ipaddr_str, INET_ADDRSTRLEN);
dbg("Applying WSC configuration (%s):\n", interface_name);
dbg(" - SSID : %s\n", ssid);
dbg(" - AUTH_TYPE : 0x%04x\n", out->auth_type);
dbg(" - ENCRYPTION_TYPE : 0x%04x\n", out->enc_type);
dbg(" - NETWORK_KEY : %s\n", network_key);
dbg(" - MAPIE_EXTENSION : 0x%02x\n", out->mapie);
dbg(" - BRIDGE : %s\n", bridge);
dbg(" - PROTO : %s\n", exts->proto);
dbg(" - VID : 0x%02x\n", exts->vid);
dbg(" - BR_IP : %s\n", ipaddr_str);
dbg(" - BAND : %s\n", band_str);
// if teardown bit is set, return
if (BIT(4, out->mapie))
return M2_PROCESS_TEARDOWN;
multi_ap |= (BIT(5, out->mapie) << 1);
multi_ap |= BIT(6, out->mapie);
snprintf(multiap_str, sizeof(multiap_str), "%d", multi_ap);
//snprintf(ipaddr_str, sizeof(ipaddr_str), "%d.%d.%d.%d", br_ip[0],
// br_ip[1], br_ip[2], br_ip[3]);
if (!get_encryption_value(out->auth_type, out->enc_type,
auth_type_str, 20)) {
info("Unsupported encryption or cipher received!!\n");
return M2_PROCESS_ERROR;
}
ret = uci_set_bridge("network", bridge, exts->proto, ipaddr_str);
if (ret) {
info("Error seting up bridge from M2!\n");
return M2_PROCESS_ERROR;
}
// Set uci in agent
ret = uci_check_wifi_iface(UCI_AGENT, interface_name,
UCI_FH_AGENT);
if (!ret) {
ret = uci_add_wireless_iface_sec(UCI_AGENT, interface_name,
UCI_FH_AGENT, NULL);
if (!ret)
return M2_PROCESS_ERROR;
}
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT, "ifname",
interface_name, "band", band_str);
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT, "ifname",
interface_name, "device", device);
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT, "ifname",
interface_name, "ssid", ssid);
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT, "ifname",
interface_name, "key", network_key);
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT, "ifname",
interface_name, "encryption", auth_type_str);
uci_set_wireless_interface_option(UCI_AGENT, UCI_FH_AGENT, "ifname",
interface_name, "multi_ap", multiap_str);
if (multi_ap & 0x01) {
char disallow_str[2] = {0};
snprintf(disallow_str, sizeof(disallow_str), "%d",
((out->mapie >> 2) & 0x03));
uci_set_wireless_interface_option(UCI_AGENT,
UCI_FH_AGENT, "ifname",
interface_name,
"disallow_bsta", disallow_str);
}
// Set uci in wireless
ret = uci_check_wifi_iface(UCI_WIRELESS, interface_name,
UCI_WLAN_IFACE);
if (!ret) {
char name[32] = {0};
snprintf(name, sizeof(name), "%s_ap", interface_name);
replace_char(name, '.', '_');
ret = uci_add_wireless_iface_sec(UCI_WIRELESS, interface_name,
UCI_WLAN_IFACE, name);
if (!ret)
return M2_PROCESS_ERROR;
}
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "network", bridge);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "ssid", (char *) ssid);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "key", (char *) network_key);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "encryption", auth_type_str);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "mode", "ap");
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "device", device);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "multi_ap", multiap_str);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "ieee80211k", "1");
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "ieee80211v", "1");
do {
char buf[512] = {0};
char basemacstr[18] = {0};
uint8_t basemac[6] = {0};
//uint8_t uuid[16] = {0};
chrCmd(buf, sizeof(buf), "db -q get hw.board.basemac");
if (buf[0] != '\0' && strlen(buf) == 17)
strncpy(basemacstr, buf, 17);
dbg("basemac: %s\n", basemacstr);
hwaddr_aton(buf, basemac);
memset(buf, 0, sizeof(buf));
chrCmd(buf, sizeof(buf),
"uuidgen -s --namespace @dns --name www.iopsys.eu");
if (buf[0] == '\0' || strlen(buf) != 36) {
dbg("uuidgen error!\n");
//TODO
}
snprintf(buf + 24, 13, "%02x%02x%02x%02x%02x%02x", MAC2STR(basemac));
dbg("UUID: %s\n", buf);
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE, "ifname",
interface_name, "uuid", buf);
} while(0);
if (multi_ap == 0x01) {
uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
"ifname", interface_name, "hidden", "1");
} else {
uci_set_wireless_interface_option(UCI_WIRELESS,
UCI_WLAN_IFACE, "ifname", interface_name, "wps", "1");
uci_set_wireless_interface_option(UCI_WIRELESS,
UCI_WLAN_IFACE, "ifname", interface_name,
"wps_pushbutton", "1");
}
/* TODO: don't support guest network for the moment */
//uci_add_dhcp(bridge);
//uci_add_fw(cfg, bridge);
return M2_PROCESS_OK;
}
/* end of functions taken from ieee1905d */
static struct netif_bkcfg *get_netif_bkcfg_by_name(struct agent_config *c,
const char *name)
{
struct netif_bkcfg *p;
list_for_each_entry(p, &c->bklist, list) {
if (!strcmp(name, p->name))
return p;
}
return NULL;
}
static struct netif_fhcfg *get_netif_fhcfg_by_name(struct agent_config *c,
const char *name)
{
struct netif_fhcfg *p;
list_for_each_entry(p, &c->fhlist, list) {
if (!strcmp(name, p->name))
return p;
}
return NULL;
}
static struct steer_policy *get_steer_policy_by_name(struct netif_fhcfg *c,
const char *name)
{
struct steer_policy *p;
if (!c)
return NULL;
list_for_each_entry(p, &c->steer_policylist, list) {
if (!strcmp(name, p->name))
return p;
}
return NULL;
}
static struct agent_config_radio *get_agent_config_radio(struct agent_config *c,
const char *ifname)
{
struct agent_config_radio *p;
list_for_each_entry(p, &c->radiolist, list) {
if (!strcmp(ifname, p->name))
return p;
}
return NULL;
}
void stax_add_entry(struct list_head *h, char *sta_macstr)
{
struct stax *n;
n = calloc(1, sizeof(struct stax));
if (n) {
snprintf(n->macstring, 18, "%s", sta_macstr);
list_add(&n->list, h);
}
}
void stax_del_entry(struct list_head *h, char *sta_macstr)
{
struct stax *s, *tmp;
list_for_each_entry_safe(s, tmp, h, list) {
if (!strncmp(s->macstring, sta_macstr, sizeof(s->macstring))) {
list_del(&s->list);
free(s);
return;
}
}
}
static int clean_steer_btm_excl(struct agent_config *p)
{
struct stax *n, *tmp;
list_for_each_entry_safe(n, tmp, &p->steer_btm_excludelist, list) {
list_del(&n->list);
free(n);
}
return 0;
}
static int clean_steer_excl(struct agent_config *p)
{
struct stax *n, *tmp;
list_for_each_entry_safe(n, tmp, &p->steer_excludelist, list) {
list_del(&n->list);
free(n);
}
return 0;
}
void agent_config_dump(struct agent_config *cfg)
{
struct netif_fhcfg *n;
struct steer_policy *pol;
struct stax *x;
if (!cfg)
return;
dbg(" Steer Exclude Lists -------\n");
list_for_each_entry(x, &cfg->steer_excludelist, list) {
dbg(" mac: %s\n", x->macstring);
}
dbg(" Steer BTM Exclude Lists -------\n");
list_for_each_entry(x, &cfg->steer_btm_excludelist, list) {
dbg(" mac: %s\n", x->macstring);
}
list_for_each_entry(n, &cfg->fhlist, list) {
dbg("name: %s\n", n->name);
dbg(" enabled : %s\n", n->enabled ? "true" : "false");
dbg(" assocctrl: %s\n", n->assoc_control ? "true" : "false");
dbg(" Policies -------\n");
list_for_each_entry(pol, &n->steer_policylist, list) {
dbg(" name: %s\n", pol->name);
dbg(" enabled : %s\n",
pol->enabled ? "true" : "false");
/* if (pol->dump_config)
* pol->dump_config(pol, pol->policy);
*/
}
dbg(" Assoc Ctrl Lists -------\n");
list_for_each_entry(x, &n->assoc_ctrllist, list) {
dbg(" mac: %s\n", x->macstring);
}
}
}
/* create fh-iface config and initialize with default values */
struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg,
const char *ifname)
{
struct netif_fhcfg *new;
struct steer_rule *r;
if (!cfg)
return NULL;
new = calloc(1, sizeof(struct netif_fhcfg));
if (!new) {
warn("OOM! config\n");
return NULL;
}
snprintf(new->name, 16, "%s", ifname);
new->enabled = true;
new->fallback_legacy = STEER_LEGACY_FALLBACK_INT;
new->steer_btm_retry_secs = STEER_BTM_RETRY_INT;
new->steer_legacy_reassoc_secs = STEER_LEGACY_REASSOC_INT;
new->steer_legacy_retry_secs = STEER_LEGACY_RETRY_INT;
new->assoc_control_time = ASSOC_CONTROL_INT;
new->band = BAND_UNKNOWN;
INIT_LIST_HEAD(&new->steer_policylist);
/* nrules = get_registered_steer_rules(&pollist); */ /* TODO */
list_for_each_entry(r, ®d_steer_rules, list) {
struct steer_policy *pol;
pol = calloc(1, sizeof(struct steer_policy));
if (!pol)
goto err_oom;
snprintf(pol->name, 16, "%s", r->name);
pol->enabled = false;
if (r->init_config)
r->init_config(r, &pol->policy);
list_add(&pol->list, &new->steer_policylist);
}
INIT_LIST_HEAD(&new->assoc_ctrllist);
/* f->cfg = new; */
dbg("%s: %s netif_fh->cfg = %p\n", __func__, new->name, new);
list_add(&new->list, &cfg->fhlist);
return new;
err_oom:
list_flush(&new->steer_policylist, struct steer_policy, list);
free(new);
return NULL;
}
/* create fh-iface config and initialize with default values */
struct netif_bkcfg *create_backhaul_iface_config(struct agent_config *cfg,
const char *ifname)
{
struct netif_bkcfg *new;
if (!cfg)
return NULL;
new = calloc(1, sizeof(struct netif_bkcfg));
if (!new) {
warn("OOM! config\n");
return NULL;
}
snprintf(new->name, 16, "%s", ifname);
new->enabled = true;
new->onboarded = false;
new->band = BAND_UNKNOWN;
/* f->cfg = new; */
dbg("%s: %s netif_fh->cfg = %p\n", __func__, new->name, new);
list_add(&new->list, &cfg->bklist);
return new;
}
static void config_update_entry(struct uci_context *ctx, struct uci_package *p,
struct uci_section *s, const char *optname,
int add, void *val, int len)
{
struct uci_ptr ptr;
memset(&ptr, 0, sizeof(struct uci_ptr));
ptr.p = p;
ptr.s = s;
ptr.package = p->e.name;
ptr.section = s->e.name;
ptr.option = optname;
ptr.target = UCI_TYPE_OPTION;
ptr.flags |= UCI_LOOKUP_EXTENDED;
ptr.value = (char *)val;
if (add) {
dbg("config: add list option: %s\n", (char *)val);
uci_add_list(ctx, &ptr);
} else {
dbg("config: del list option: %s\n", (char *)val);
uci_del_list(ctx, &ptr);
}
uci_commit(ctx, &p, false);
}
int config_update(const char *confname, struct agent_config *cfg,
const char *section, const char *option,
int add,
void *value, int len)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg = NULL;
struct uci_element *e;
ctx = uci_alloc_context();
if (ctx && uci_load(ctx, confname, &pkg) != UCI_OK) {
dbg("config file '%s' not found!\n", confname);
free(ctx);
return -1;
}
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
struct uci_element *x, *tmp;
struct uci_option *op;
if (strcmp(s->type, section))
continue;
/* iter through matched 'section' for the 'option' */
uci_foreach_element_safe(&s->options, tmp, x) {
if (strcmp(x->name, option))
continue;
op = uci_to_option(x);
if (op->type == UCI_TYPE_LIST) {
uci_foreach_element(&op->v.list, x) {
if (!strncmp(x->name, value, len)) {
if (!add)
config_update_entry(ctx,
pkg, s,
option, 0,
value, len);
goto out_exit;
}
}
/* add new exclude at end of list */
if (add)
config_update_entry(ctx, pkg, s, option,
1, value, len);
goto out_exit;
}
}
/* 'option' name not present in 'section'
* Create a new one at end of 'section'.
*/
if (add)
config_update_entry(ctx, pkg, s, option, 1, value, len);
goto out_exit;
}
out_exit:
uci_free_context(ctx);
return 0;
}
int config_update2(const char *confname, struct agent_config *cfg,
const char *section_type,
const char *match_option,
const char *match_option_value,
const char *option,
int add,
void *value, int len)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg = NULL;
struct uci_element *e;
ctx = uci_alloc_context();
if (ctx && uci_load(ctx, confname, &pkg) != UCI_OK) {
dbg("config file '%s' not found!\n", confname);
free(ctx);
return -1;
}
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
struct uci_element *x, *tmp;
struct uci_option *op;
const char *optstring;
if (strcmp(s->type, section_type))
continue;
if (match_option && match_option_value) {
optstring = uci_lookup_option_string(ctx, s,
match_option);
if (!optstring || strcmp(optstring, match_option_value))
continue;
}
/* iter through matched 'section' for the 'option' */
uci_foreach_element_safe(&s->options, tmp, x) {
if (strcmp(x->name, option))
continue;
op = uci_to_option(x);
if (op->type == UCI_TYPE_LIST) {
uci_foreach_element(&op->v.list, x) {
if (!strncmp(x->name, value, len)) {
if (!add) {
config_update_entry(ctx,
pkg, s, option,
0, value, len);
}
goto out_exit;
}
}
/* add new 'option' at end of list */
if (add) {
config_update_entry(ctx, pkg, s, option,
1, value, len);
}
goto out_exit;
}
}
/* 'option' name not present in 'section'
* Create a new one at end of 'section'.
*/
if (add)
config_update_entry(ctx, pkg, s, option,
1, value, len);
goto out_exit;
}
out_exit:
uci_free_context(ctx);
return 0;
}
#if 0
struct config uci_config = {
.name = "uci",
.priv = uci_ctx;
.get = uci_get_config,
.set = uci_set_config,
.init = uci_setup,
.exit = uci_exit,
};
#define priv_get_config(priv) container_of(priv, struct config, priv)
void register_config(struct config *c)
{
static struct uci_context *ctx;
static struct uci_package *pkg;
struct uci_element *e;
int ret = 0;
if (uci_ctx)
return priv_get_config(uci_ctx);
ctx = uci_alloc_context();
if (ctx) {
uci_ctx = ctx;
memcpy(c, &uci_config, sizeof(*cfg));
}
if (uci_load(ctx, "wifiagent", &pkg))
return -1;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
const char *option_val;
if (strcmp(s->type, "wifiagent"))
continue;
option_val = uci_lookup_option_string(ctx, s, name);
if (option_val)
sprintf(val, "%s", option_val);
else
ret = -1;
}
uci_free_context(ctx);
return ret;
}
#endif
static int agent_config_get_wifi_agent(struct agent_config *a,
struct uci_section *s)
{
enum {
A_ENABLED,
A_DEBUG,
A_PROFILE,
A_BRCM_SETUP,
/*A_CONFIGURED,*/
A_CNTLR_MAC,
A_EXCLUDE,
A_EXCLUDE_BTM,
A_AL_BRIDGE,
A_NETDEV,
NUM_POLICIES
};
const struct uci_parse_option opts[] = {
{ .name = "enabled", .type = UCI_TYPE_STRING },
{ .name = "debug", .type = UCI_TYPE_STRING },
{ .name = "profile", .type = UCI_TYPE_STRING },
{ .name = "brcm_setup", .type = UCI_TYPE_STRING },
/*{ .name = "configured", .type = UCI_TYPE_STRING },*/
{ .name = "controller_macaddr", .type = UCI_TYPE_STRING },
{ .name = "exclude", .type = UCI_TYPE_LIST },
{ .name = "exclude_btm", .type = UCI_TYPE_LIST },
{ .name = "al_bridge", .type = UCI_TYPE_STRING },
{ .name = "netdev", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_POLICIES];
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[A_ENABLED])
a->enabled = atoi(tb[A_ENABLED]->v.string) == 1 ? true : false;
if (tb[A_DEBUG]) {
a->debug_level = atoi(tb[A_DEBUG]->v.string);
if (verbose < a->debug_level)
verbose = a->debug_level;
}
if (tb[A_PROFILE])
a->profile = atoi(tb[A_PROFILE]->v.string);
if (tb[A_BRCM_SETUP])
a->brcm_setup = atoi(tb[A_BRCM_SETUP]->v.string);
/*if (tb[A_CONFIGURED])
a->configured = atoi(tb[A_CONFIGURED]->v.string);*/
if (tb[A_CNTLR_MAC])
hwaddr_aton(tb[A_CNTLR_MAC]->v.string, a->cntlr_almac);
if (tb[A_EXCLUDE]) {
struct uci_element *xi;
dbg("Steer: exclude: ");
uci_foreach_element(&tb[A_EXCLUDE]->v.list, xi) {
dbg("%s ", xi->name);
stax_add_entry(&a->steer_excludelist, xi->name);
}
dbg("\n");
}
if (tb[A_EXCLUDE_BTM]) {
struct uci_element *xi;
dbg("Steer: exclude_btm: ");
uci_foreach_element(&tb[A_EXCLUDE_BTM]->v.list, xi) {
dbg("%s ", xi->name);
stax_add_entry(&a->steer_btm_excludelist, xi->name);
}
dbg("\n");
}
if (tb[A_AL_BRIDGE]) {
const char *iface;
iface = tb[A_AL_BRIDGE]->v.string;
strncpy(a->al_bridge, iface, sizeof(a->al_bridge) - 1);
} else /* Default to br-lan if non-specfied */
strncpy(a->al_bridge, "br-lan", sizeof(a->al_bridge) - 1);
if (tb[A_NETDEV]) {
const char *ifname;
ifname = tb[A_NETDEV]->v.string;
strncpy(a->netdev, ifname, sizeof(a->netdev) - 1);
} else { /* Default to wl/wlan if not specfied */
strncpy(a->netdev, (a->brcm_setup)?"wl":"wlan", sizeof(a->netdev) - 1);
}
return 0;
}
static int agent_config_get_controller_select(struct agent_config *a,
struct uci_section *s)
{ enum {
CTRL_SELECT_LOCAL,
CTRL_SELECT_ID,
CTRL_SELECT_PROBE_INT,
CTRL_SELECT_RETRY_INT,
CTRL_SELECT_AUTOSTART,
NUM_CTRL_SELECT_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "local", .type = UCI_TYPE_STRING },
{ .name = "id", .type = UCI_TYPE_STRING },
{ .name = "probe_int", .type = UCI_TYPE_STRING },
{ .name = "retry_int", .type = UCI_TYPE_STRING },
{ .name = "autostart", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_CTRL_SELECT_POLICIES];
struct ctrl_select_cfg *cscfg;
uci_parse_section(s, opts, NUM_CTRL_SELECT_POLICIES, tb);
cscfg = (struct ctrl_select_cfg *)calloc(1, sizeof(struct ctrl_select_cfg));
if (!cscfg)
return -1;
if (!tb[CTRL_SELECT_LOCAL]) {
warn("Required option 'local' not found!\n");
return -1;
}
cscfg->local = atoi(tb[CTRL_SELECT_LOCAL]->v.string);
if (tb[CTRL_SELECT_ID]) {
cscfg->auto_detect = true;
if (strncmp(tb[CTRL_SELECT_ID]->v.string, "auto", 4)) {
cscfg->auto_detect = false;
hwaddr_aton(tb[CTRL_SELECT_ID]->v.string, cscfg->alid);
}
}
if (tb[CTRL_SELECT_PROBE_INT])
cscfg->probe_int = atoi(tb[CTRL_SELECT_PROBE_INT]->v.string);
if (tb[CTRL_SELECT_RETRY_INT])
cscfg->retry_int = atoi(tb[CTRL_SELECT_RETRY_INT]->v.string);
if (tb[CTRL_SELECT_AUTOSTART])
cscfg->autostart = atoi(tb[CTRL_SELECT_AUTOSTART]->v.string);
if (a->cscfg)
free(a->cscfg);
a->cscfg = cscfg;
return 0;
}
static int agent_config_get_wifi_radio(struct agent_config *a,
struct uci_section *s)
{
enum {
WIFI_RADIO_DEVICE,
WIFI_RADIO_BAND,
WIFI_RADIO_CONFIGURED,
WIFI_RADIO_ONBOARDED,
NUM_WIFI_RADIO_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "device", .type = UCI_TYPE_STRING },
{ .name = "band", .type = UCI_TYPE_STRING },
{ .name = "configured", .type = UCI_TYPE_STRING },
{ .name = "onboarded", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_WIFI_RADIO_POLICIES];
const char *ifname = NULL;
uint32_t band = 0;
struct agent_config_radio *n;
uci_parse_section(s, opts, NUM_WIFI_RADIO_POLICIES, tb);
if (!tb[WIFI_RADIO_DEVICE] || !tb[WIFI_RADIO_BAND]) {
warn("No radio name or band option found!\n");
return -1;
}
if (tb[WIFI_RADIO_DEVICE])
ifname = tb[WIFI_RADIO_DEVICE]->v.string;
if (tb[WIFI_RADIO_BAND]) {
band = atoi(tb[WIFI_RADIO_BAND]->v.string);
if (band != 2 && band != 5) {
warn("Incorrect band '%d' in config\n", band);
return -1;
}
}
if (ifname && band) {
n = get_agent_config_radio(a, ifname);
if (!n) {
n = calloc(1, sizeof(*n));
if (!n) {
warn("-ENOMEM!\n");
return -1;
}
list_add_tail(&n->list, &a->radiolist);
}
strncpy(n->name, ifname, 16);
n->name[15] = '\0';
n->band = band;
}
if (tb[WIFI_RADIO_CONFIGURED]) {
n->configured = atoi(tb[WIFI_RADIO_CONFIGURED]->v.string) == 1 ?
true : false;
}
if (tb[WIFI_RADIO_ONBOARDED]) {
n->onboarded = atoi(tb[WIFI_RADIO_ONBOARDED]->v.string) == 1 ?
true : false;
}
return 0;
}
static int agent_config_get_bk_iface(struct agent_config *a,
struct uci_section *s)
{
enum {
BK_IFNAME,
BK_DEVICE,
BK_BAND,
BK_ENABLED,
BK_ONBOARDED,
BK_SSID,
BK_KEY,
BK_ENCRYPTION,
BK_DISALLOWED_BSTA_P1,
BK_DISALLOWED_BSTA_P2,
NUM_POLICIES
};
const struct uci_parse_option opts[] = {
{ .name = "ifname", .type = UCI_TYPE_STRING },
{ .name = "device", .type = UCI_TYPE_STRING },
{ .name = "band", .type = UCI_TYPE_STRING },
{ .name = "enabled", .type = UCI_TYPE_STRING },
{ .name = "onboarded", .type = UCI_TYPE_STRING },
{ .name = "ssid", .type = UCI_TYPE_STRING },
{ .name = "key", .type = UCI_TYPE_STRING },
{ .name = "encryption", .type = UCI_TYPE_STRING },
{ .name = "disallow_bsta_p1", .type = UCI_TYPE_STRING },
{ .name = "disallow_bsta_p2", .type = UCI_TYPE_STRING }
};
struct uci_option *tb[NUM_POLICIES];
struct netif_bkcfg *bk;
const char *ifname;
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[BK_IFNAME]) {
ifname = tb[BK_IFNAME]->v.string;
bk = get_netif_bkcfg_by_name(a, ifname);
if (!bk) {
bk = create_backhaul_iface_config(a, ifname);
if (!bk) {
warn("%s: OOM!\n", __func__);
return -1;
}
} else {
warn("Duplicate 'bk-iface %s' config!! ignore\n",
ifname);
}
} else {
warn("No ifname in bk-iface section!\n");
return -1;
}
if (tb[BK_DEVICE]) {
const char *device;
device = tb[BK_DEVICE]->v.string;
strncpy(bk->device, device, sizeof(bk->device) - 1);
}
if (tb[BK_ENABLED])
bk->enabled = atoi(tb[BK_ENABLED]->v.string);
if (tb[BK_ONBOARDED])
bk->onboarded = atoi(tb[BK_ONBOARDED]->v.string);
if (tb[BK_BAND]) {
int band = atoi(tb[BK_BAND]->v.string);
if (band == 2)
bk->band = BAND_2;
else if (band == 5)
bk->band = BAND_5;
}
if (tb[BK_SSID]) {
const char *ssid;
ssid = tb[BK_SSID]->v.string;
strncpy(bk->ssid, ssid, sizeof(bk->ssid) - 1);
}
if (tb[BK_KEY]) {
const char *key;
key = tb[BK_KEY]->v.string;
strncpy(bk->key, key, sizeof(bk->key) - 1);
}
if (tb[BK_ENCRYPTION]) {
const char *encryption;
encryption = tb[BK_ENCRYPTION]->v.string;
strncpy(bk->encryption, encryption, sizeof(bk->encryption) - 1);
}
if (tb[BK_DISALLOWED_BSTA_P1])
bk->disallowed_bsta_p1 =
atoi(tb[BK_DISALLOWED_BSTA_P1]->v.string);
if (tb[BK_DISALLOWED_BSTA_P2])
bk->disallowed_bsta_p2 =
atoi(tb[BK_DISALLOWED_BSTA_P2]->v.string);
return 0;
}
static int agent_config_get_fh_iface(struct agent_config *a,
struct uci_section *s)
{
enum {
FH_IFNAME,
FH_BAND,
FH_STEER,
FH_DEVICE,
FH_ASSOC_CTRL,
FH_BTM_RETRY,
FH_BTM_RETRY_SECS,
FH_FLBK_LEGACY,
FH_STEER_LEGACY_RASSOC_SECS,
FH_STEER_LEGACY_RETRY_SECS,
FH_ASSOC_CTRL_SECS,
FH_SSID,
FH_KEY,
FH_ENCRYPTION,
FH_POLICY,
FH_UTIL_THRESHOLD,
FH_RCPI_THRESHOLD,
FH_REPORT_RCPI_THRESHOLD,
FH_RCPI_HYSTERESIS_MARGIN,
FH_REPORT_UTIL_THRESHOLD,
FH_INCLUDE_STA_STATS,
FH_INCLUDE_STA_METRIC,
NUM_POLICIES,
};
const struct uci_parse_option opts[] = {
{ .name = "ifname", .type = UCI_TYPE_STRING },
{ .name = "band", .type = UCI_TYPE_STRING },
{ .name = "steer", .type = UCI_TYPE_LIST },
{ .name = "device", .type = UCI_TYPE_STRING },
{ .name = "assoc_ctrl", .type = UCI_TYPE_LIST },
{ .name = "btm_retry", .type = UCI_TYPE_STRING },
{ .name = "btm_retry_secs", .type = UCI_TYPE_STRING },
{ .name = "fallback_legacy", .type = UCI_TYPE_STRING },
{ .name = "steer_legacy_reassoc_secs", .type = UCI_TYPE_STRING },
{ .name = "steer_legacy_retry_secs", .type = UCI_TYPE_STRING },
{ .name = "assoc_ctrl_secs", .type = UCI_TYPE_STRING },
{ .name = "ssid", .type = UCI_TYPE_STRING },
{ .name = "key", .type = UCI_TYPE_STRING },
{ .name = "encryption", .type = UCI_TYPE_STRING },
{ .name = "policy", .type = UCI_TYPE_STRING },
{ .name = "util_threshold", .type = UCI_TYPE_STRING },
{ .name = "rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "report_rcpi_threshold", .type = UCI_TYPE_STRING },
{ .name = "rcpi_hysteresis_margin", .type = UCI_TYPE_STRING },
{ .name = "report_util_threshold", .type = UCI_TYPE_STRING },
{ .name = "include_sta_stats", .type = UCI_TYPE_STRING },
{ .name = "include_sta_metric", .type = UCI_TYPE_STRING }
};
struct uci_option *tb[NUM_POLICIES];
struct netif_fhcfg *fh;
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (tb[FH_IFNAME]) {
const char *ifname;
ifname = tb[FH_IFNAME]->v.string;
fh = get_netif_fhcfg_by_name(a, ifname);
if (!fh) {
fh = create_fronthaul_iface_config(a, ifname);
if (!fh) {
warn("%s: OOM!\n", __func__);
return -1;
}
} else {
warn("Duplicate 'fh-iface %s' config!! ignore\n",
ifname);
}
} else {
warn("No ifname in fh-iface section!\n");
return -1;
}
if (tb[FH_BAND]) {
int band = atoi(tb[FH_BAND]->v.string);
if (band == 2)
fh->band = BAND_2;
else if (band == 5)
fh->band = BAND_5;
}
if (tb[FH_STEER]) {
struct uci_element *xi;
dbg("Steer: param: ");
uci_foreach_element(&tb[FH_STEER]->v.list, xi) {
struct steer_policy *p = NULL;
struct steer_rule *r;
dbg("%s ", xi->name);
p = get_steer_policy_by_name(fh, xi->name);
if (!p) {
/* TODO? */
dbg("TODO!! steer before ifname\n");
continue;
}
p->enabled = true;
r = get_steer_rule_by_name(xi->name);
if (r)
r->enabled = true;
}
dbg("\n");
}
if (tb[FH_DEVICE]) {
const char *device;
device = tb[FH_DEVICE]->v.string;
strncpy(fh->device, device, sizeof(fh->device) - 1);
}
if (tb[FH_BTM_RETRY])
fh->steer_btm_retry = atoi(tb[FH_BTM_RETRY]->v.string);
if (tb[FH_BTM_RETRY_SECS])
fh->steer_btm_retry_secs = atoi(tb[FH_BTM_RETRY_SECS]->v.string);
if (tb[FH_FLBK_LEGACY])
fh->fallback_legacy = atoi(tb[FH_FLBK_LEGACY]->v.string);
if (tb[FH_STEER_LEGACY_RASSOC_SECS])
fh->steer_legacy_reassoc_secs =
atoi(tb[FH_STEER_LEGACY_RASSOC_SECS]->v.string);
if (tb[FH_STEER_LEGACY_RETRY_SECS])
fh->steer_legacy_retry_secs =
atoi(tb[FH_STEER_LEGACY_RETRY_SECS]->v.string);
if (tb[FH_ASSOC_CTRL_SECS])
fh->assoc_control_time =
atoi(tb[FH_ASSOC_CTRL_SECS]->v.string);
if (tb[FH_SSID]) {
const char *ssid;
ssid = tb[FH_SSID]->v.string;
strncpy(fh->ssid, ssid, sizeof(fh->ssid) - 1);
}
if (tb[FH_KEY]) {
const char *key;
key = tb[FH_KEY]->v.string;
strncpy(fh->key, key, sizeof(fh->key) - 1);
}
if (tb[FH_ENCRYPTION]) {
const char *encryption;
encryption = tb[FH_ENCRYPTION]->v.string;
strncpy(fh->encryption, encryption, sizeof(fh->encryption) - 1);
}
if (tb[FH_POLICY])
fh->policy = atoi(tb[FH_POLICY]->v.string);
if (tb[FH_UTIL_THRESHOLD])
fh->util_threshold = atoi(tb[FH_UTIL_THRESHOLD]->v.string);
if (tb[FH_RCPI_THRESHOLD])
fh->rcpi_threshold = atoi(tb[FH_RCPI_THRESHOLD]->v.string);
if (tb[FH_REPORT_RCPI_THRESHOLD])
fh->report_rcpi_threshold =
atoi(tb[FH_REPORT_RCPI_THRESHOLD]->v.string);
if (tb[FH_RCPI_HYSTERESIS_MARGIN])
fh->rcpi_hysteresis_margin =
atoi(tb[FH_RCPI_HYSTERESIS_MARGIN]->v.string);
if (tb[FH_REPORT_UTIL_THRESHOLD])
fh->report_util_threshold =
atoi(tb[FH_REPORT_UTIL_THRESHOLD]->v.string);
if (tb[FH_INCLUDE_STA_STATS])
fh->include_sta_stats =
atoi(tb[FH_INCLUDE_STA_STATS]->v.string);
if (tb[FH_INCLUDE_STA_METRIC])
fh->include_sta_metric =
atoi(tb[FH_INCLUDE_STA_METRIC]->v.string);
return 0;
}
static int agent_config_get_steer_param(struct agent_config *a,
struct uci_section *s)
{
struct steer_rule *r;
dbg("Steer-param: %s\n", s->e.name);
r = get_steer_rule_by_name(s->e.name);
if (!r)
return -1;
dbg("Rule to handle steer-param '%s' available\n", s->e.name);
r->config(r, a, s);
return 0;
}
static int agent_config_get_policy_param(struct agent_config *a,
struct uci_section *s)
{
enum {
POL_REPORT_INTERVAL,
POL_PVID,
POL_PCP_DEFAULT,
POL_REPORT_SCAN,
POL_REPORT_STA_ASSOCFAILS,
POL_REPORT_STA_ASSOCFAILS_RATE,
NUM_POLICIES
};
const struct uci_parse_option opts[] = {
{ .name = "report_interval", .type = UCI_TYPE_STRING },
{ .name = "pvid", .type = UCI_TYPE_STRING },
{ .name = "pcp_default", .type = UCI_TYPE_STRING },
{ .name = "repost_scan", .type = UCI_TYPE_STRING },
{ .name = "report_sta_assocfails", .type = UCI_TYPE_STRING },
{ .name = "report_sta_assocfails_rate", .type = UCI_TYPE_STRING },
};
struct uci_option *tb[NUM_POLICIES];
struct policy_cfg *cfg;
uci_parse_section(s, opts, NUM_POLICIES, tb);
cfg = (struct policy_cfg *)calloc(1, sizeof(struct policy_cfg));
if (!cfg)
return -1;
if (tb[POL_REPORT_INTERVAL])
cfg->report_interval = atoi(tb[POL_REPORT_INTERVAL]->v.string);
if (tb[POL_PVID])
cfg->pvid = atoi(tb[POL_PVID]->v.string);
if (tb[POL_PCP_DEFAULT])
cfg->pcp_default = atoi(tb[POL_PCP_DEFAULT]->v.string);
if (tb[POL_REPORT_SCAN])
cfg->report_scan = atoi(tb[POL_REPORT_SCAN]->v.string);
if (tb[POL_REPORT_STA_ASSOCFAILS])
cfg->report_sta_assocfails =
atoi(tb[POL_REPORT_STA_ASSOCFAILS]->v.string);
if (tb[POL_REPORT_STA_ASSOCFAILS_RATE])
cfg->report_sta_assocfails_rate =
atoi(tb[POL_REPORT_STA_ASSOCFAILS_RATE]->v.string);
if (a->pcfg)
free(a->pcfg);
a->pcfg = cfg;
return 0;
}
int agent_config_reload(struct agent_config *cfg)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
cfg->enabled = false;
cfg->runfreq = AGENT_RUN_AUTO;
ctx = uci_alloc_context();
if (!ctx)
return -1;
if (uci_load(ctx, "mapagent", &pkg)) {
uci_free_context(ctx);
return -1;
}
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, "agent"))
agent_config_get_wifi_agent(cfg, s);
else if (!strcmp(s->type, "controller_select"))
agent_config_get_controller_select(cfg, s);
else if (!strcmp(s->type, "wifi-radio"))
agent_config_get_wifi_radio(cfg, s);
else if (!strcmp(s->type, "fh-iface"))
agent_config_get_fh_iface(cfg, s);
else if (!strcmp(s->type, "bk-iface"))
agent_config_get_bk_iface(cfg, s);
else if (!strcmp(s->type, "steer"))
agent_config_get_steer_param(cfg, s);
else if (!strcmp(s->type, "policy"))
agent_config_get_policy_param(cfg, s);
}
uci_free_context(ctx);
return 0;
}
int config_generate_radio(struct agent_config *cfg, struct uci_context *ctx,
char *device, uint8_t band)
{
struct uci_package *pkg;
struct uci_section *s;
int rv;
rv = uci_load(ctx, UCI_AGENT, &pkg);
if (rv)
return -1;
s = config_add_section(ctx, pkg, UCI_AGENT, "wifi-radio", "device",
device);
if (!s)
return -1;
if (band == BAND_2)
set_value(ctx, pkg, s, "band", "2", UCI_TYPE_STRING);
else if (band == BAND_5)
set_value(ctx, pkg, s, "band", "5", UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
return 0;
}
int config_generate_bsta_agent(struct agent_config *cfg, struct uci_context *ctx,
const char *device, const char *ifname,
uint8_t band)
{
struct uci_section *s;
struct uci_package *pkg;
int rv;
rv = uci_load(ctx, UCI_AGENT, &pkg);
if (rv)
return -1;
s = config_add_section(ctx, pkg, UCI_AGENT, UCI_BK_AGENT, "device",
device);
if (!s)
return -1;
if (band == BAND_2)
set_value(ctx, pkg, s, "band", "2", UCI_TYPE_STRING);
else if (band == BAND_5)
set_value(ctx, pkg, s, "band", "5", UCI_TYPE_STRING);
set_value(ctx, pkg, s, "ifname", ifname, UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
return 0;
}
int config_find_radio(struct agent_config *cfg, struct uci_context *ctx,
char *radio)
{
struct uci_package *pkg;
struct uci_section *s;
struct uci_element *e;
bool found = false;
int rv;
rv = uci_load(ctx, UCI_AGENT, &pkg);
if (rv)
return found;
s = config_get_section(ctx, pkg, "wifi-radio", "device", radio);
if (s)
found = true;
uci_unload(ctx, pkg);
return found;
}
static void wifi_radio_status_cb(struct ubus_request *req, int type,
struct blob_attr *msg)
{
struct blob_attr *tb[1];
static const struct blobmsg_policy ap_attr[1] = {
[0] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
};
char band_str[8] = {0};
uint8_t *band = req->priv;
blobmsg_parse(ap_attr, 1, tb, blob_data(msg), blob_len(msg));
if (!tb[0])
return;
strncpy(band_str, blobmsg_data(tb[0]), sizeof(band_str));
if (!strncmp(band_str, "5GHz", sizeof(band_str)))
*band = BAND_5;
else if (!strncmp(band_str, "2.4GHz", sizeof(band_str)))
*band = BAND_2;
else
*band = BAND_UNKNOWN;
}
void config_disable_bstas(struct agent_config *cfg)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_section *section;
struct netif_bkcfg *bk;
bool reload = false;
list_for_each_entry(bk, &cfg->bklist, list) {
/* only disable onboarded bsta */
// if (!bk->cfg->onboarded)
// continue;
/* disable from wireless config */
pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
if (!pkg)
continue;
section = config_get_section(ctx, pkg, UCI_WLAN_IFACE, "ifname", bk->name);
if (!section) {
uci_unload(ctx, pkg);
continue;
}
set_value(ctx, pkg, section, "disabled", "1", UCI_TYPE_STRING);
uci_save(ctx, pkg);
reload = true;
}
if (reload) {
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
}
list_for_each_entry(bk, &cfg->bklist, list) {
pkg = uci_load_pkg(&ctx, UCI_AGENT);
if (!pkg)
continue;
section = config_get_section(ctx, pkg, UCI_BK_AGENT, "ifname", bk->name);
if (!section) {
uci_unload(ctx, pkg);
continue;
}
set_value(ctx, pkg, section, "enabled", "0", UCI_TYPE_STRING);
uci_save(ctx, pkg);
bk->enabled = 0;
}
if (reload) {
uci_commit(ctx, &pkg, false);
uci_reload_services("wireless");
}
uci_free_context(ctx);
}
int config_disable_bsta(struct netif_bkcfg *bk)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_section *section;
int ret = -1;
/* disable mapagent bk-iface section */
pkg = uci_load_pkg(&ctx, UCI_AGENT);
if (!pkg)
return -1;
section = config_get_section(ctx, pkg, UCI_BK_AGENT, "ifname", bk->name);
if (!section)
goto out_pkg;
set_value(ctx, pkg, section, "enabled", "0", UCI_TYPE_STRING);
uci_save(ctx, pkg);
bk->enabled = 0;
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
/* disable wireless config bsta wifi-iface section */
pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
if (!pkg)
goto out;
section = config_get_section(ctx, pkg, UCI_WLAN_IFACE, "ifname", bk->name);
if (!section)
goto out_pkg;
set_value(ctx, pkg, section, "disabled", "1", UCI_TYPE_STRING);
uci_save(ctx, pkg);
uci_commit(ctx, &pkg, false);
ret = 0;
out_pkg:
uci_unload(ctx, pkg);
out:
uci_free_context(ctx);
return ret;
}
bool config_find_bsta_agent(struct agent_config *cfg, struct uci_context *ctx,
char *device)
{
struct uci_package *pkg;
struct uci_element *e;
struct uci_section *section = NULL;
int rv;
bool found = false;
rv = uci_load(ctx, UCI_AGENT, &pkg);
if (rv)
return found;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
char *c_device;
if (strncmp(s->type, UCI_BK_AGENT, strlen(UCI_BK_AGENT)))
continue;
c_device = uci_lookup_option_string(ctx, s, "device");
if (!c_device)
continue;
if (strncmp(device, c_device, 16))
continue;
found = true;
break;
}
uci_unload(ctx, pkg);
return found;
}
struct uci_section *config_find_bsta_wireless(struct agent_config *cfg,
struct uci_context *ctx, struct uci_package *pkg, const char *device)
{
struct uci_element *e;
int rv;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
char *c_device, *mode;
if (strncmp(s->type, UCI_WLAN_IFACE, strlen(UCI_WLAN_IFACE)))
continue;
c_device = uci_lookup_option_string(ctx, s, "device");
if (!c_device || strncmp(device, c_device, 16))
continue;
mode = uci_lookup_option_string(ctx, s, "mode");
if (!mode || strcmp(mode, "sta"))
continue;
return s;
}
return NULL;
}
int agent_config_prepare(struct agent_config *cfg)
{
// TODO: iterate through 'wifi-device' sections in wireless config.
// If corresponding 'wifi-radio <device-name>' section is not available
// in 'mapagent' config, create one. Check supported bands of the new
// wifi-device and add option 'band' to the wifi-radio section.
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_element *e;
struct blob_buf bb = {0};
pkg = uci_load_pkg(&ctx, UCI_WIRELESS);
if (!pkg)
return -1;
blob_buf_init(&bb, 0);
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
struct uci_section *wl_s;
const char *device, *ifname;
uint8_t band = 0;
char obj_name[64] = {0};
int rv;
if (strncmp(s->type, UCI_WL_DEVICE, strlen(UCI_WL_DEVICE)))
continue;
device = s->e.name;
snprintf(obj_name, sizeof(obj_name), "wifi.radio.%s",
device);
rv = ubus_call(obj_name, "status", &bb,
wifi_radio_status_cb, &band);
if (rv)
continue;
if (!config_find_radio(cfg, ctx, device))
config_generate_radio(cfg, ctx, device, band);
if (config_find_bsta_agent(cfg, ctx, device))
continue;
wl_s = config_find_bsta_wireless(cfg, ctx, pkg, device);
if (!wl_s)
continue;
ifname = uci_lookup_option_string(ctx, wl_s, "ifname");
if (!ifname)
continue;
config_generate_bsta_agent(cfg, ctx, device, ifname, band);
}
blob_buf_free(&bb);
uci_unload(ctx, pkg);
uci_free_context(ctx);
return 0;
}
int agent_config_init(struct agent_config *cfg)
{
INIT_LIST_HEAD(&cfg->fhlist);
INIT_LIST_HEAD(&cfg->bklist);
INIT_LIST_HEAD(&cfg->radiolist);
INIT_LIST_HEAD(&cfg->steer_excludelist);
INIT_LIST_HEAD(&cfg->steer_btm_excludelist);
agent_config_prepare(cfg);
agent_config_reload(cfg);
return 0;
}
void clean_bk(struct netif_bkcfg *p)
{
list_del(&p->list);
free(p);
}
int clean_all_bk(struct agent_config *cfg)
{
struct netif_bkcfg *p, *tmp;
list_for_each_entry_safe(p, tmp, &cfg->bklist, list)
clean_bk(p);
return 0;
}
void clean_fh(struct netif_fhcfg *p)
{
list_del(&p->list);
free(p);
}
int clean_all_fh(struct agent_config *cfg)
{
struct netif_fhcfg *p, *tmp;
list_for_each_entry_safe(p, tmp, &cfg->fhlist, list)
clean_fh(p);
return 0;
}
void clean_radio_cfg(struct agent_config_radio *p)
{
list_del(&p->list);
free(p);
}
int clean_all_radios(struct agent_config *cfg)
{
struct agent_config_radio *p, *tmp;
list_for_each_entry_safe(p, tmp, &cfg->radiolist, list)
clean_radio_cfg(p);
return 0;
}
int agent_config_clean(struct agent_config *cfg)
{
clean_all_fh(cfg);
clean_all_bk(cfg);
clean_steer_btm_excl(cfg);
clean_steer_excl(cfg);
clean_all_radios(cfg);
if (cfg->pcfg)
free(cfg->pcfg);
return 0;
}
int wifi_reorder_interfaces_by_device(struct agent_config *ac,
struct uci_context *ctx, struct uci_package *pkg, char *device)
{
int i, j = 0;
int devnum = 0;
char ifname[IFNAMSIZ] = {0};
enum {
W_IFNAME,
NUM_POLICIES
};
const struct uci_parse_option opts[] = {
{ .name = "ifname", .type = UCI_TYPE_STRING }
};
struct uci_option *tb[NUM_POLICIES];
struct uci_element *e;
trace("reordering interfaces for device %s\n", device);
devnum = get_device_num_from_name(device);
snprintf(ifname, IFNAMSIZ, "%s%d",
ac->netdev,
devnum);
for (i = 1; i < 16; i++) {
trace("iterating in search of %s\n", ifname);
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (strncmp(s->type, UCI_WLAN_IFACE,
strlen(UCI_WLAN_IFACE)))
continue;
uci_parse_section(s, opts, NUM_POLICIES, tb);
if (!tb[W_IFNAME])
continue;
if (strncmp(tb[W_IFNAME]->v.string, ifname, sizeof(ifname)))
continue;
trace("found interface %s, reordering to %d\n", ifname, j);
uci_reorder_section(ctx, s, j);
j++;
break;
}
snprintf(ifname, IFNAMSIZ, "%s%d%s%d",
ac->netdev,
devnum,
(ac->brcm_setup ? "." : "_"),
i);
}
return 0;
}
int wifi_reorder_interfaces(struct agent_config *ac)
{
struct uci_context *ctx;
struct uci_package *pkg;
struct uci_element *e;
ctx = uci_alloc_context();
if (!ctx)
return -1;
if (uci_load(ctx, UCI_WIRELESS, &pkg)) {
uci_free_context(ctx);
return -1;
}
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (strncmp(s->type, UCI_WL_DEVICE, strlen(UCI_WL_DEVICE)))
continue;
wifi_reorder_interfaces_by_device(ac, ctx, pkg, s->e.name);
}
uci_commit(ctx, &pkg, false);
uci_free_context(ctx);
return 0;
}
int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_element *e;
struct uci_section *section = NULL;
/** if bridge starts with br prefix, step past */
if (!strncmp(bridge, "br-", 3))
bridge += 3;
pkg = uci_load_pkg(&ctx, "network");
if (!pkg)
return -1;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (strncmp(s->e.name, bridge, 16))
continue;
section = s;
break;
}
if (!section) {
struct uci_ptr ptr = {0};
ptr.p = pkg;
ptr.section = bridge;
ptr.value = "interface";
ptr.option = NULL;
uci_set(ctx, &ptr);
section = ptr.s;
}
set_value(ctx, pkg, section, "type", "bridge", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "is_lan", "1", UCI_TYPE_STRING);
if (strlen(proto))
set_value(ctx, pkg, section, "proto", proto, UCI_TYPE_STRING);
if (!strcmp(proto, "static")) {
set_value(ctx, pkg, section, "ipaddr", ipaddress,
UCI_TYPE_STRING);
set_value(ctx, pkg, section, "netmask", "255.255.255.0",
UCI_TYPE_STRING);
}
uci_commit(ctx, &pkg, false);
uci_unload(ctx, pkg);
uci_free_context(ctx);
return false;
}
int uci_add_dhcp(char *iface)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_element *e;
struct uci_section *section = NULL;
struct uci_ptr ptr = {0};
/** if bridge starts with br prefix, step past */
if (!strncmp(iface, "br-", 3))
iface += 3;
pkg = uci_load_pkg(&ctx, "dhcp");
if (!pkg)
return -1;
uci_foreach_element(&pkg->sections, e) {
struct uci_section *s = uci_to_section(e);
if (strncmp(s->e.name, iface, 16))
continue;
trace("Existing section found for ifname %s\n", iface);
goto out;
}
trace("Adding DHCP section for ifname %s\n", iface);
ptr.p = pkg;
ptr.section = iface;
ptr.value = "dhcp";
ptr.option = NULL;
uci_set(ctx, &ptr);
section = ptr.s;
set_value(ctx, pkg, section, "interface", iface, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "start", "100", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "limit", "150", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "leasetime", "1h", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "dhcpv6", "server", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "ra", "server", UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
out:
uci_unload(ctx, pkg);
uci_free_context(ctx);
return false;
}
int uci_add_fw(struct agent_config *cfg, char *iface)
{
struct uci_context *ctx = NULL;
struct uci_package *pkg;
struct uci_element *e;
struct uci_section *section = NULL;
int rv;
/** if bridge starts with br prefix, step past */
if (!strncmp(iface, "br-", 3))
iface += 3;
pkg = uci_load_pkg(&ctx, "firewall");
if (!pkg)
return -1;
section = config_get_section(ctx, pkg, "zone", "name", iface);
if (!section) {
trace("No fw section found for %s\n", iface);
rv = uci_add_section(ctx, pkg, "zone", §ion);
if (rv)
goto out_pkg;
set_value(ctx, pkg, section, "name", iface, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "network", iface, UCI_TYPE_LIST);
set_value(ctx, pkg, section, "input", "ACCEPT", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "output", "ACCEPT", UCI_TYPE_STRING);
set_value(ctx, pkg, section, "forward", "ACCEPT", UCI_TYPE_STRING);
rv = uci_save(ctx, pkg);
if (rv)
goto out_pkg;
uci_commit(ctx, &pkg, false);
}
section = config_get_section(ctx, pkg, "forwarding", "src", iface);
if (!section) {
//section = config_add_section(ctx, pkg, "firewall", "forwarding", "src", iface);
//if (!section)
// goto out;
rv = uci_add_section(ctx, pkg, "forwarding", §ion);
if (rv)
goto out_pkg;
set_value(ctx, pkg, section, "src", iface, UCI_TYPE_STRING);
set_value(ctx, pkg, section, "dest", cfg->al_bridge, UCI_TYPE_STRING);
uci_commit(ctx, &pkg, false);
}
out_pkg:
uci_unload(ctx, pkg);
uci_free_context(ctx);
return false;
}