diff --git a/src/Makefile b/src/Makefile
index b4964b3fc672485d42678c438d8e8925a92e40ef..24642f6a2de239b5ab8b8a31e1209f2eb6e1446d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -7,7 +7,6 @@ OBJS = \
utils/liblist.o \
utils/utils.o \
-
IPC_OBJS = \
ipc/comm.o \
ipc/worker.o \
@@ -19,6 +18,7 @@ AGENT_OBJS = \
core/agent_ubus.o \
core/agent.o \
core/agent_map.o \
+ core/agent_tlv_generator.o \
core/config.o \
core/main.o \
core/plugin.o
@@ -26,6 +26,7 @@ AGENT_OBJS = \
LIBS = -lubus -lubox -ljson-c -lblobmsg_json -luci -lwifi-6 -leasy -pthread
LIBS += -rdynamic -ldl
LIBS += -lmaputils
+LIBS += -lwsc
plugin_subdirs ?= $(wildcard plugins/*)
plugin_sofile = $(wildcard $(d)/*.so)
@@ -36,13 +37,13 @@ plugin_files = $(foreach d, $(plugin_subdirs), $(plugin_sofile))
all: $(EXECS) plugins utils/libeasyutils.so
-
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
mapagent: $(OBJS) $(IPC_OBJS) $(AGENT_OBJS)
$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
plugins:
@echo "$(plugin_subdirs)"
for i in $(plugin_subdirs); do [ -d $$i ] && $(MAKE) -C $$i all; done
diff --git a/src/agent.conf b/src/agent.conf
index 5779c0c589b218c5c88522a2ab87ffbe8aa85415..5d6f795baef2a2eaf8cd2d75752ab6a9a7ad4426 100644
--- a/src/agent.conf
+++ b/src/agent.conf
@@ -15,17 +15,20 @@ config fh-iface
option steer_legacy_reassoc_secs '30'
option steer_legacy_retry_secs '3600'
option assoc_ctrl_secs '30'
+ option band '2'
config fh-iface
option ifname 'wl1'
option steer 'rssi bssload'
list exclude '00:11:22:33:44:55'
list exclude_btm '00:aa:bb:cc:dd:ee'
+ option band '5'
#config bk-iface
# option ifname 'apclii0'
# option enabled '1'
# option onboarded '0'
+# option disallow_bsta '1 # bitmap, 1 for disallow p1, 2 to disallow p2, 3 to disallow both (probably never applicable)
config steer-param 'rssi'
option priority '0'
diff --git a/src/core/agent.c b/src/core/agent.c
index 9b44ff1bbb4501c513f930e5ba7a703b79f919d5..c3cae9a4de1d5f365e53d07e1dab88e0642c1099 100644
--- a/src/core/agent.c
+++ b/src/core/agent.c
@@ -29,6 +29,13 @@
#include <pthread.h>
+#include <map1905/map2.h>
+#include <map1905/maputils.h>
+#include <easy/easy.h>
+#include <wifi.h>
+
+#include <wsc.h>
+
#include "utils/utils.h"
#include "map_module.h"
#include "utils.h"
@@ -1400,7 +1407,7 @@ static int wifi_parse_frame(struct agent *a, struct json_object *frameobj)
{
struct wifi_assoc_frame *new, *old;
struct sta *s;
- char *assoc, *framestr;
+ const char *framestr;
uint8_t *frame;
int len;
@@ -1459,7 +1466,6 @@ static void wifi_iface_event_handler(void *c, struct blob_attr *msg)
{
struct agent *a = (struct agent *)c;
const char *ifname, *event;
- unsigned char mac[6];
struct json_object *jmsg, *data;
char *str;
@@ -1635,8 +1641,6 @@ static void wifi_radio_event_handler(void *c, struct blob_attr *msg)
static void wifi_wps_creds_event_handler(void *c, struct blob_attr *msg)
{
- struct agent *a = (struct agent *)c;
- struct netif_fh *fh;
char encryption[32] = {0}, ifname[16] = {0}, ssid[33] = {0},
key[64] = {0};
struct blob_attr *tb[4];
@@ -1737,7 +1741,6 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
if (tb[1])
mid = (uint16_t)blobmsg_get_u32(tb[1]);
-
if (tb[2])
strncpy(in_ifname, blobmsg_data(tb[2]), 15);
@@ -1761,9 +1764,9 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
}
strtob(tlvstr, len, tlv);
+ free(tlvstr);
}
-
#if 0
if (tb[4]) {
int rem;
@@ -1791,7 +1794,7 @@ static void ieee1905_cmdu_event_handler(void *c, struct blob_attr *msg)
#endif
agent_handle_map_event(a, type, mid, in_ifname, srcmac, tlv, len);
-
+ free(tlv);
}
static void ubus_1905_event_handler(struct ubus_context *ctx,
@@ -2190,100 +2193,132 @@ static int run_agent(struct agent *a)
return 0;
}
+static void parse_al_mac(struct ubus_request *req, int type,
+ struct blob_attr *msg)
+{
+ struct agent *a = (struct agent *)req->priv;
+ struct blob_attr *tb[1];
+ static const struct blobmsg_policy ieee_attrs[1] = {
+ [0] = { .name = "ieee1905id", .type = BLOBMSG_TYPE_STRING },
+ };
+
+ blobmsg_parse(ieee_attrs, 1, tb, blob_data(msg), blob_len(msg));
+
+ if (tb[0]) {
+ char *mac;
+
+ mac = blobmsg_get_string(tb[0]);
+ hwaddr_aton(mac, a->al_mac);
+ dbg("almac = " MACFMT "\n", MAC2STR(a->al_mac));
+ }
+}
+
static void parse_radio(struct ubus_request *req, int type,
struct blob_attr *msg)
{
struct wifi_radio_element *re = (struct wifi_radio_element *)req->priv;
- struct blob_attr *tb[7], *cur, *cur1;
- int rem, j = 0, rem1, k = 0;
- static const struct blobmsg_policy radio_attr[7] = {
+ struct blob_attr *tb[8];
+ static const struct blobmsg_policy radio_attr[8] = {
[0] = { .name = "isup", .type = BLOBMSG_TYPE_BOOL },
- [1] = { .name = "noise", .type = BLOBMSG_TYPE_INT32 },
- [2] = { .name = "rx_streams", .type = BLOBMSG_TYPE_INT8 },
- [3] = { .name = "tx_streams", .type = BLOBMSG_TYPE_INT8 },
- [4] = { .name = "supp_channels", .type = BLOBMSG_TYPE_ARRAY },
- [5] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
- [6] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }
+ [1] = { .name = "band", .type = BLOBMSG_TYPE_STRING },
+ [2] = { .name = "noise", .type = BLOBMSG_TYPE_INT32 },
+ [3] = { .name = "rx_streams", .type = BLOBMSG_TYPE_INT8 },
+ [4] = { .name = "tx_streams", .type = BLOBMSG_TYPE_INT8 },
+ [5] = { .name = "supp_channels", .type = BLOBMSG_TYPE_ARRAY },
+ [6] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
+ [7] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 },
};
- blobmsg_parse(radio_attr, 7, tb, blob_data(msg), blob_len(msg));
+ blobmsg_parse(radio_attr, 8, tb, blob_data(msg), blob_len(msg));
if (tb[0])
re->enabled = blobmsg_get_bool(tb[0]);
- if (tb[1])
- re->anpi = (int) blobmsg_get_u32(tb[1]); // no get int?
+ if (tb[1]) {
+ char *band;
+
+ band = blobmsg_get_string(tb[1]);
+ if (!strncmp(band, "2.4GHz", strlen("2.4GHz")))
+ re->band = BAND_2;
+ else if (!strncmp(band, "5GHz", strlen("5GHz")))
+ re->band = BAND_5;
+ else
+ re->band = BAND_UNKNOWN;
+ }
if (tb[2])
- re->rx_streams = blobmsg_get_u8(tb[2]);
+ re->anpi = (int) blobmsg_get_u32(tb[2]); // no get int?
if (tb[3])
re->rx_streams = blobmsg_get_u8(tb[3]);
- if (tb[4]) {
- re->num_supp_opclass = blobmsg_check_array(tb[4], BLOBMSG_TYPE_TABLE);
+ if (tb[4])
+ re->rx_streams = blobmsg_get_u8(tb[4]);
+
+ if (tb[5]) {
+ int rem, rem1, i = 0;
+ struct blob_attr *cur;
+
+ re->num_supp_opclass = blobmsg_check_array(tb[5], BLOBMSG_TYPE_TABLE);
re->supp_opclass = calloc(re->num_supp_opclass, sizeof(*re->supp_opclass));
if (!re->supp_opclass) {
fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
return;
}
- blobmsg_for_each_attr(cur, tb[4], rem) {
- struct blob_attr *data[3];
+ blobmsg_for_each_attr(cur, tb[5], rem) {
+ struct blob_attr *data[3], *cur1;
static const struct blobmsg_policy supp_attrs[3] = {
[0] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 },
[1] = { .name = "txpower", .type = BLOBMSG_TYPE_INT32 },
[2] = { .name = "channels", .type = BLOBMSG_TYPE_ARRAY }
};
+ int k = 0;
- k = 0;
if (blobmsg_type(cur) != BLOBMSG_TYPE_TABLE)
continue;
- // for whatever reason it may continue parsing next object
- if (!data[0] || !data[1] || j >= re->num_supp_opclass)
- continue;
-
blobmsg_parse(supp_attrs, 3, data, blobmsg_data(cur),
- blobmsg_data_len(cur));
- if (data[0])
- re->supp_opclass[j].id = (uint8_t) blobmsg_get_u32(data[0]);
+ blobmsg_data_len(cur));
+
+ if (!data[0] || !data[1] || i >= re->num_supp_opclass)
+ continue;
- if (data[1])
- re->supp_opclass[j].max_txpower = blobmsg_get_u32(data[1]);
+ re->supp_opclass[i].id = (uint8_t) blobmsg_get_u32(data[0]);
+ re->supp_opclass[i].max_txpower = (int8_t) blobmsg_get_u32(data[1]);
if (data[2])
- re->supp_opclass[j].num_supported_channels = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32);
+ re->supp_opclass[i].num_supported_channels = blobmsg_check_array(data[2], BLOBMSG_TYPE_INT32);
- re->supp_opclass[j].supp_chanlist = calloc(re->supp_opclass[j].num_supported_channels, sizeof(uint8_t));
- if (!re->supp_opclass[j].supp_chanlist) {
+ re->supp_opclass[i].supp_chanlist = calloc(re->supp_opclass[i].num_supported_channels, sizeof(uint8_t));
+ if (!re->supp_opclass[i].supp_chanlist) {
fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
return;
}
- blobmsg_for_each_attr(cur1, data[2], rem1) {
- //struct blob_attr *data1;
- re->supp_opclass[j].supp_chanlist[k++] = blobmsg_get_u32(cur1);
- }
+ blobmsg_for_each_attr(cur1, data[2], rem1)
+ re->supp_opclass[i].supp_chanlist[k++] = blobmsg_get_u32(cur1);
- re->supp_opclass[j].num_exclude_channels = 1;
- if (re->supp_opclass[j].num_exclude_channels > 0) {
- re->supp_opclass[j].exclude_chanlist =
- (uint8_t *)calloc(re->supp_opclass[j].num_exclude_channels,
+ re->supp_opclass[i].num_exclude_channels = 1;
+ if (re->supp_opclass[i].num_exclude_channels > 0) {
+ re->supp_opclass[i].exclude_chanlist =
+ (uint8_t *)calloc(re->supp_opclass[i].num_exclude_channels,
sizeof(uint8_t));
- if (re->supp_opclass[j].exclude_chanlist) {
- memcpy(re->supp_opclass[j].exclude_chanlist,
- "\x5d",
- re->supp_opclass[j].num_exclude_channels * sizeof(uint8_t));
+ if (re->supp_opclass[i].exclude_chanlist) {
+ memcpy(re->supp_opclass[i].exclude_chanlist,
+ "\x5d",
+ re->supp_opclass[i].num_exclude_channels * sizeof(uint8_t));
}
}
- j++;
+ i++;
}
}
- if (tb[5])
- re->current_opclass = (uint8_t) blobmsg_get_u32(tb[5]);
+
if (tb[6])
- re->current_channel = (uint8_t) blobmsg_get_u32(tb[6]);
+ re->current_opclass = (uint8_t) blobmsg_get_u32(tb[6]);
+
+ if (tb[7])
+ re->current_channel = (uint8_t) blobmsg_get_u32(tb[7]);
}
static void _enumerate_wifi_objects(struct ubus_request *req, int type,
@@ -2437,11 +2472,21 @@ static struct netif_bk *netif_alloc_bk(const char *ifname)
return n;
}
-static void netif_free(const char *ifname)
+static void netif_free(struct netif_fh *n)
{
+ list_del(&n->list);
+ free(n);
/* TODO? */
}
+static void netif_free_all(struct agent *a)
+{
+ struct netif_fh *p, *tmp;
+
+ list_for_each_entry_safe(p, tmp, &a->fhlist, list)
+ netif_free(p);
+}
+
const char *wifi_ifname_to_radio(struct agent *a, char *ifname)
{
int i, j;
@@ -2465,7 +2510,7 @@ struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
char *ifname)
{
int i;
- char *radio;
+ const char *radio;
radio = wifi_ifname_to_radio(a, ifname);
if (!radio)
@@ -2488,10 +2533,9 @@ struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a,
struct netif_fh *wifi_radio_to_ap(struct agent *a, const char *radio)
{
struct netif_fh *p;
- struct sta *s;
list_for_each_entry(p, &a->fhlist, list) {
- char *fh_radio;
+ const char *fh_radio;
fh_radio = wifi_ifname_to_radio(a, p->name);
if (!fh_radio)
@@ -2576,14 +2620,13 @@ static void parse_ap(struct ubus_request *req, int type,
hwaddr_aton(bssid, fh->bssid);
if (tb[2]) {
- struct blob_attr *data[2], *caps, *attr;
+ struct blob_attr *data[2];
static const struct blobmsg_policy cap_attr[2] = {
[0] = { .name = "dot11n", .type = BLOBMSG_TYPE_TABLE },
[1] = { .name = "dot11ac", .type = BLOBMSG_TYPE_TABLE }
};
- int rv, rem;
- rv = blobmsg_parse(cap_attr, 2, data, blobmsg_data(tb[2]),
+ blobmsg_parse(cap_attr, 2, data, blobmsg_data(tb[2]),
blobmsg_data_len(tb[2]));
if (data[0])
@@ -2610,6 +2653,15 @@ static int agent_init_interfaces(struct agent *a)
struct netif_fhcfg *f;
struct netif_bkcfg *b;
wifi_object_t wifi_obj;
+ uint32_t ieee1905_obj;
+
+ ieee1905_obj = ubus_get_object(a->ubus_ctx, "ieee1905");
+ if (ieee1905_obj != WIFI_OBJECT_INVALID) {
+ ubus_call_object(a, ieee1905_obj, "info", parse_al_mac, a);
+ } else {
+ warn("Object '%s' not present!\n");
+ return -1;
+ }
wifi_obj = ubus_get_object(a->ubus_ctx, "wifi");
if (wifi_obj != WIFI_OBJECT_INVALID) {
@@ -2786,6 +2838,16 @@ int agent_msgqueue_dispatcher(void *data)
return ret;
}
+void clear_fhlist(struct agent *a)
+{
+ struct netif_fh *p, *tmp;
+
+ list_for_each_entry_safe(p, tmp, &a->fhlist, list) {
+ list_del(&p->list);
+ free(p);
+ }
+}
+
int start_agent(void)
{
struct agent *w;
@@ -2830,14 +2892,14 @@ int start_agent(void)
ubus_add_uloop(ctx);
- agent_config_reload(&w->cfg);
+ agent_config_init(&w->cfg);
+ //agent_config_reload(&w->cfg);
//agent_config_defaults(w, &w->cfg);
#if 0
agent_config_reload("wifiagent", &w->cfg);
agent_config_reload("wireless", &w->cfg);
agent_config_dump(&w->cfg);
#endif
-
get_registered_steer_rules(); /* TODO: return rule list and improve */
agent_init_interfaces(w);
@@ -2868,13 +2930,40 @@ int start_agent(void)
ubus_free(ctx);
uloop_done();
/* TODO: cleanups */
+ clear_fhlist(w);
free(w);
return 0;
}
+void agent_free_radios(struct agent *a)
+{
+ int i;
+
+ for (i = 0; i < a->num_radios; i++) {
+ struct wifi_radio_element *re;
+ int j;
+
+ re = &a->radios[i];
+
+ for (j = 0; j < re->num_supp_opclass; j++)
+ free(re->supp_opclass[j].exclude_chanlist);
+
+ free(re->supp_opclass);
+
+ // theoretically should be allocated or NULL
+ if (re->autconfig.m1_frame)
+ free(re->autconfig.m1_frame);
+ if (re->autconfig.key) {
+ free(re->autconfig.key->key);
+ free(re->autconfig.key);
+ }
+ }
+}
+
void stop_agent(struct agent *w)
{
+
if (!w) {
warn("%s: (agent = NULL)\n", __func__);
exit(0);
@@ -2885,12 +2974,19 @@ void stop_agent(struct agent *w)
*/
//exit_dispatcher(w);
+
+ stop_test_logging();
worker_exit(&w->cmd_dispatcher);
ubus_unregister_event_handler(w->ubus_ctx, &w->wifi_evh);
ubus_unregister_event_handler(w->ubus_ctx, &w->ieee1905_evh);
- agent_remove_object(w->ubus_ctx);
+ plugins_unload(&w->pluginlist);
+ agent_remove_object(w);
ubus_free(w->ubus_ctx);
uloop_done();
+ agent_config_clean(&w->cfg);
+ agent_free_radios(w);
+ clear_fhlist(w);
+ netif_free_all(w);
free(w);
}
@@ -3756,7 +3852,6 @@ int wifiagent_process_cmd_async(struct ubus_context *ctx,
int cmd_id, char *cmd_data, int len)
{
struct agent *a = this_agent;
- int ret = 0;
struct msg *msg;
trace_cmd("Agent: Recvd CMD async %s payload_sz = %d\n",
diff --git a/src/core/agent.h b/src/core/agent.h
index 09902861221ed2f4f4b3dd10c21c96e82a1bdc6c..013c6d4dbb428e96b7726864963f2f2b7517b260 100644
--- a/src/core/agent.h
+++ b/src/core/agent.h
@@ -13,6 +13,10 @@
#include <easy/easy.h>
#include <wifi.h>
+// TODO: TODO: fixme: remove this include
+//#include <ieee1905/1905_tlvs.h>
+
+
typedef char timestamp_t[32];
typedef struct ip_address {
@@ -318,6 +322,7 @@ struct wifi_unassoc_sta_element {
struct wifi_radio_element {
char name[16];
uint8_t macaddr[6];
+ enum wifi_band band;
bool enabled;
int anpi;
uint8_t total_utilization; /** in %age, linearly scaled 0..255 */
@@ -345,6 +350,12 @@ struct wifi_radio_element {
struct wifi_bss_element *bsslist;
struct wifi_scanres_element *scanlist;
struct wifi_unassoc_sta_element *unassoc_stalist;
+
+ struct {
+ uint8_t *m1_frame;
+ uint16_t m1_size;
+ struct wsc_key *key;
+ } autconfig;
};
struct wifi_netdev {
@@ -358,6 +369,7 @@ struct wifi_netdev {
/** struct agent - wifi agent */
struct agent {
int debug;
+ uint8_t al_mac[6];
struct uloop_timeout heartbeat;
struct list_head fhlist;
struct list_head bklist;
@@ -412,6 +424,7 @@ extern void wifiagent_notify_event(struct agent *a, void *ev_type,
#endif
extern int plugins_load(int argc, char *argv[], struct list_head *plugins);
+extern int plugins_unload(struct list_head *plugins);
struct netif_fh *wifi_radio_to_ap(struct agent *a, const char *radio);
diff --git a/src/core/agent_map.c b/src/core/agent_map.c
index 446634eeb00e816b744612988fb0b02d91a3f681..be223e5723987bd35b512f1bf4b216000a386c79 100644
--- a/src/core/agent_map.c
+++ b/src/core/agent_map.c
@@ -17,6 +17,12 @@
#include <net/if_arp.h>
#include <pthread.h>
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+#define TMP_WIFI_IFACE_MAX_NUM 16
+
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
@@ -29,6 +35,8 @@
#include <libubus.h>
+#include <uci.h>
+
#include "map_module.h"
#include "utils.h"
#include "debug.h"
@@ -39,10 +47,13 @@
#include "msgqueue.h"
#include "worker.h"
#include "agent.h"
-
+//#include "platform_interfaces.h"
#include <map1905/map2.h>
#include <map1905/maputils.h>
+#include <wsc.h>
+
+#include "agent_tlv_generator.h"
#define UBUS_TIMEOUT 1000
@@ -63,6 +74,21 @@ typedef int (*map_cmdu_sendfunc_t)(void *agent, struct cmdu_cstruct *cmdu);
int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu);
+uint8_t *extract_tlv_by_type(struct cmdu_cstruct *cmdu, uint8_t tlv_type)
+{
+ uint8_t *tlv;
+ int i;
+
+ for (i = 0; i < cmdu->num_tlvs; i++) {
+ tlv = cmdu->tlvs[i];
+ if (*tlv == tlv_type)
+ return tlv;
+ }
+
+ return NULL;
+
+}
+
/* lookup netif struct by bssid */
static struct netif_fh *get_netif_by_bssid(struct agent *a, uint8_t *bssid)
{
@@ -78,6 +104,76 @@ static struct netif_fh *get_netif_by_bssid(struct agent *a, uint8_t *bssid)
return NULL;
}
+int build_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *rec_cmdu,
+ struct wifi_radio_element *radio, int idx)
+{
+ struct agent *a = (struct agent *) agent;
+ struct cmdu_cstruct *cmdu;
+ struct tlv_ap_radio_basic_cap *p;
+ struct tlv_profile2_ap_cap *p1;
+ struct tlv_ap_radio_adv_cap *p2;
+ struct tlv_wsc *p3;
+ int tlv_index = 0;
+ uint16_t len = 0;
+
+ cmdu = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
+ if (!cmdu) {
+ fprintf(stderr, "failed to malloc cmdu\n");
+ return -1;
+ }
+
+ memcpy(cmdu->origin, rec_cmdu->origin, 6);
+ cmdu->message_type = CMDU_TYPE_AP_AUTOCONFIGURATION_WSC;
+ cmdu->message_id = rec_cmdu->message_id;
+ strncpy(cmdu->intf_name, rec_cmdu->intf_name,
+ sizeof(cmdu->intf_name) - 1);
+
+ p = agent_gen_ap_radio_basic_cap(a, cmdu, idx);
+ if (!p)
+ goto fail_cmdu;
+ cmdu->num_tlvs++;
+
+ p1 = agent_gen_profile2_ap_cap(a, cmdu);
+ if (!p1)
+ goto fail_p;
+ cmdu->num_tlvs++;
+
+ p2 = agent_gen_ap_radio_adv_cap(a, cmdu, radio);
+ if (!p2)
+ goto fail_p1;
+ cmdu->num_tlvs++;
+
+ p3 = agent_gen_wsc(a, cmdu, radio);
+ if (!p3)
+ goto fail_p2;
+ cmdu->num_tlvs++;
+
+ cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, sizeof(uint8_t *));
+ if (!cmdu->tlvs)
+ goto fail_p3;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p;
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
+ // TODO: ff:ff:ff:ff:ff:ff = send to all agents
+
+ agent_send_cmdu(a, cmdu);
+ map_free_cmdu(cmdu);
+ return 0;
+fail_p3:
+ map_free_tlv_cstruct((uint8_t *) p3);
+fail_p2:
+ map_free_tlv_cstruct((uint8_t *) p2);
+fail_p1:
+ map_free_tlv_cstruct((uint8_t *) p1);
+fail_p:
+ map_free_tlv_cstruct((uint8_t *) p);
+fail_cmdu:
+ free(cmdu);
+ return -1;
+}
+
int send_topology_notification(void *agent, struct cmdu_cstruct *cmdu)
{
return 0;
@@ -249,154 +345,301 @@ int handle_topology_response(void *agent, struct cmdu_cstruct *cmdu)
int handle_ap_autoconfig_search(void *agent, struct cmdu_cstruct *cmdu)
{
- trace("%s: --->\n", __func__);
+ trace("agent: %s: --->\n", __func__);
return 0;
}
int handle_ap_autoconfig_response(void *agent, struct cmdu_cstruct *cmdu)
{
- trace("%s: --->\n", __func__);
+ trace("agent: %s: --->\n", __func__);
+ struct agent *a = (struct agent *) agent;
+ struct wifi_radio_element *radio;
+ int i;
+
+ for (i = 0; i < a->num_radios; i++) {
+ radio = a->radios + i;
+ build_ap_autoconfig_wsc(a, cmdu, radio, i);
+ }
return 0;
}
-int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
+static struct wifi_radio_element *wifi_get_radio_by_mac(struct agent *a,
+ uint8_t *hwaddr)
{
- trace("%s: --->\n", __func__);
- return 0;
-}
+ struct wifi_radio_element *radio;
+ int i;
+ for (i = 0; i < a->num_radios; i++) {
+ radio = a->radios + i;
-int handle_1905_ack(void *agent, struct cmdu_cstruct *cmdu)
+ if (memcmp(radio->macaddr, hwaddr, 6))
+ continue;
+
+ return radio;
+ }
+
+ return NULL;
+}
+
+int wifi_teardown_iface(const char *ifname)
{
- trace("%s: --->\n", __func__);
+ config_del_iface("wireless", "wifi-iface", ifname);
+ config_del_iface("ieee1905", "wifi-iface", ifname);
+ config_del_iface("agent", "fh-iface", ifname);
+
return 0;
}
-static void get_ap_vht_caps(struct agent *a,
- struct tlv_ap_vht_cap *p, uint32_t radio_index)
+int wifi_teardown_map_ifaces_by_band(struct agent *a, enum wifi_band band)
{
- struct wifi_radio_element *radio = a->radios + radio_index;
- struct netif_fh *fh;
+ struct netif_fhcfg *fh, *fh_tmp;
+ struct netif_bkcfg *bk, *bk_tmp;
- trace("%s -----> parsing radio %s\n", __func__, radio->name);
+ list_for_each_entry_safe(fh, fh_tmp, &a->cfg.fhlist, list) {
+ if (fh->band != band)
+ continue;
- fh = wifi_radio_to_ap(a, radio->name);
- if (!fh)
- return;
+ wifi_teardown_iface(fh->name);
+ clean_fh(fh);
+ }
- memcpy(p->radio_id, radio->macaddr, 6);
- memcpy(&p->vht_tx_mcs_supported, &fh->caps.mcs.vht_mcs_txmap, 2);
- memcpy(&p->vht_rx_mcs_supported, &fh->caps.mcs.vht_mcs_rxmap, 2);
- p->max_tx_streams_supported = (fh->tx_spatial_streams - 1);
- p->max_rx_streams_supported = (fh->rx_spatial_streams - 1);
- p->gi_80_support = fh->caps.vht[4] & (1 << 1) ? 1 : 0;
- p->gi_160_support = fh->caps.vht[4] & (1 << 0) ? 1 : 0;
- p->vht_8080_support = fh->caps.vht[5] & (1 << 7) ? 1 : 0;
- p->vht_160_support = fh->caps.vht[5] & (1 << 6) ? 1 : 0;
- p->su_beamformer_capable = fh->caps.vht[5] & (1 << 5) ? 1 : 0;
- p->mu_beamformer_capable = fh->caps.vht[5] & (1 << 4) ? 1 : 0;
+ list_for_each_entry_safe(bk, bk_tmp, &a->cfg.bklist, list) {
+ if (bk->band != band)
+ continue;
+
+ wifi_teardown_iface(bk->name);
+ clean_bk(bk);
+ }
+
+ agent_config_reload(&a->cfg);
+
+ return 0;
}
-static void get_ap_ht_caps(struct agent *a,
- struct tlv_ap_ht_cap *p, uint32_t radio_index)
-{
- struct wifi_radio_element *radio;
- struct netif_fh *fh;
+/* return true if valid ifname is available */
+int check_wireless_ifname(struct agent *a, const char *device,
+ const char *ifname)
+{
+ enum {
+ W_IFNAME,
+ W_DEV,
+ NUM_POLICIES
+ };
+ const struct uci_parse_option opts[] = {
+ { .name = "ifname", .type = UCI_TYPE_STRING },
+ { .name = "device", .type = UCI_TYPE_STRING }
+ };
+ struct uci_option *tb[NUM_POLICIES];
+ struct uci_context *ctx;
+ struct uci_package *pkg;
+ struct uci_element *e;
+ bool rv = false;
+ int num_ifs = 0;
+
+ ctx = uci_alloc_context();
+ if (!ctx)
+ return -1;
- radio = a->radios + radio_index;
+ if (uci_load(ctx, "wireless", &pkg)) {
+ uci_free_context(ctx);
+ return -1;
+ }
- trace("%s -----> parsing radio %s\n", __func__, radio->name);
+ uci_foreach_element(&pkg->sections, e) {
+ struct uci_section *s = uci_to_section(e);
- fh = wifi_radio_to_ap(a, radio->name);
- if (!fh)
- return;
+ if (strncmp(s->type, "wifi-iface", strlen("wifi-iface")))
+ continue;
- memcpy(p->radio_id, radio->macaddr, 6);
- p->max_tx_streams_supported = (radio->tx_streams - 1) & 0xff;
- p->max_rx_streams_supported = (radio->rx_streams - 1) & 0xff;
- p->gi_20_support = fh->caps.ht & (1 << 3) ? 1 : 0;
- p->gi_40_support = fh->caps.ht & (1 << 2) ? 1 : 0;
- p->ht_40_support = fh->caps.ht & (1 << 1) ? 1 : 0;
+ uci_parse_section(s, opts, NUM_POLICIES, tb);
+
+ if (tb[W_DEV]) {
+ const char *cfg_dev;
+
+ cfg_dev = tb[W_DEV]->v.string;
+ if (!strncmp(cfg_dev, device, IFNAMSIZ))
+ num_ifs++;
+ }
+
+ /* TODO: should work with 16 instead of 4 */
+ if (num_ifs >= TMP_WIFI_IFACE_MAX_NUM) {
+ rv = true;
+ break;
+ }
+
+ if (tb[W_IFNAME]) {
+ char *cfg_ifname;
+
+ cfg_ifname = tb[W_IFNAME]->v.string;
+ if (!strncmp(cfg_ifname, ifname, IFNAMSIZ)) {
+ rv = true;
+ break;
+ }
+ }
+ }
+
+ uci_free_context(ctx);
+ return rv;
}
-static void get_ap_radio_basic_cap(struct agent *a,
- struct tlv_ap_radio_basic_cap *p,
- uint32_t radio_index)
+/* return ifname buffer */
+char *wifi_gen_first_ifname(struct agent *a, char *device, char *ifname)
{
- uint32_t j;
- struct wifi_radio_element *radio = a->radios + radio_index;
+ int i;
- trace("%s -----> parsing radio %s\n", __func__, radio->name);
+ /* maximum number of interface per BSSID is currently 4
+ * setting a higher number may cause segfault within libwsc.so,
+ * caused by DH_free() from platform_cyrpto.c in
+ * PLATFORM_COMPUTE_DH_SHARED_SECRET() (verified with i <= 8)
+ */
+ /* TODO: should work with 16 instead of 4 */
+ for (i = 1; i <= TMP_WIFI_IFACE_MAX_NUM; i++) {
+ snprintf(ifname, IFNAMSIZ, "%s_%d", device, i);
+ if (!check_wireless_ifname(a, device, ifname))
+ return ifname;
+ }
- memcpy(p->radio_id, radio->macaddr, 6);
- p->max_bss_nr = 4; // Max BSS per Radio
- p->operating_classes_nr = radio->num_supp_opclass;
+ return NULL;
+}
- if (p->operating_classes_nr > 0)
- p->operating_class = calloc(p->operating_classes_nr,
- sizeof(*p->operating_class));
- if (!p->operating_class) {
- fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
- p->operating_classes_nr = 0;
- return;
- }
+int handle_ap_autoconfig_wsc(void *agent, struct cmdu_cstruct *cmdu)
+{
+ struct agent *a = (struct agent *) agent;
+ uint8_t bssid[6];
+ int i;
+ uint8_t *tlv = NULL;
+ struct wifi_radio_element *radio;
+ struct tlv_ap_radio_identifier *id_tlv;
+
+ trace("%s: --->\n", __func__);
+
+ id_tlv = (struct tlv_ap_radio_identifier *) extract_tlv_by_type(cmdu,
+ MAP_TLV_AP_RADIO_IDENTIFIER);
+ if (!id_tlv)
+ return -1;
+
+ memcpy(bssid, id_tlv->radio_id, 6);
+
+ radio = wifi_get_radio_by_mac(a, bssid);
+ if (!radio)
+ return -1;
+
+ wifi_teardown_map_ifaces_by_band(a, radio->band);
+
+ // need iterate every TLV_TYPE_WSC, may be multiple
+ for (i = 0; i < cmdu->num_tlvs; i++) {
+ tlv = cmdu->tlvs[i];
+ switch (*tlv) {
+ case TLV_TYPE_WSC: {
+ struct mdata out;
+ struct tlv_wsc *m2;
+ char ifname[IFNAMSIZ] = {0};
+ int rv;
+
+ m2 = (struct tlv_wsc *) tlv;
+
+ if (!wifi_gen_first_ifname(a, radio->name, ifname)) {
+ err("Failed to find valid interface name, "\
+ "probably maximum number of "\
+ "interfaces have been reached\n",
+ MACFMT "!\n", MAC2STR(bssid));
+ return -1;
+ }
- for (j = 0; j < p->operating_classes_nr; j++) {
- p->operating_class[j].op_class = radio->supp_opclass[j].id;
- p->operating_class[j].max_tx_power = radio->supp_opclass[j].max_txpower;
- p->operating_class[j].non_op_ch_nr = radio->supp_opclass[j].num_exclude_channels;
- if (p->operating_class[j].non_op_ch_nr > 0) {
- p->operating_class[j].channel =
- (uint8_t *)calloc(p->operating_class[j].non_op_ch_nr,
- sizeof(uint8_t));
- if (p->operating_class[j].channel) {
- memcpy(p->operating_class[j].channel, radio->supp_opclass[j].exclude_chanlist,
- p->operating_class[j].non_op_ch_nr);
+ rv = wscProcessM2((void *) radio->autconfig.key,
+ radio->autconfig.m1_frame,
+ radio->autconfig.m1_size,
+ m2->wsc_frame,
+ m2->wsc_frame_size, &out, ifname);
+ if (!rv) {
+ err("Failed to process M2 target for interface"\
+ MACFMT "!\n", MAC2STR(bssid));
+ //wifi_teardown_iface(ifname);
+ wifi_teardown_map_ifaces_by_band(a, radio->band);
+ // Return rather than freeing because it may belong to an updated frame
+ return -1;
}
+
+ if (BIT(3, out.output.mapie)) {
+ err("MAP Extension had teardown bit set, "\
+ "tearing down all MAP interfaces"\
+ " for bssid" MACFMT "\n",
+ MAC2STR(bssid));
+ wifi_teardown_map_ifaces_by_band(a, radio->band);
+ goto teardown;
+ }
+
+ uci_apply_m2(ifname, out.output.ssid, out.output.bssid,
+ out.output.auth_types,
+ out.output.encryption_types,
+ out.output.network_key,
+ out.output.mapie, radio->band);
+
+ break;
+ }
+ default:
+ break;
+
}
}
+
+teardown:
+ // TODO: freeing from here risks freeing an updated frame
+ free(radio->autconfig.m1_frame);
+ free(radio->autconfig.key->key);
+ free(radio->autconfig.key);
+ radio->autconfig.key = NULL;
+ radio->autconfig.m1_frame = NULL;
+ return 0;
+}
+
+
+int handle_1905_ack(void *agent, struct cmdu_cstruct *cmdu)
+{
+ trace("agent: %s: --->\n", __func__);
+ return 0;
}
int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
{
- trace("%s: --->\n", __func__);
+ trace("agent: %s: --->\n", __func__);
struct agent *a = (struct agent *) agent;
uint16_t tlv_index = 0;
uint32_t j;
- struct cmdu_cstruct *cmdu_data;
+ struct cmdu_cstruct *cmdu;
+ struct tlv_ap_cap *p2;
int ret;
- cmdu_data = (struct cmdu_cstruct *)calloc(1,
+ cmdu = (struct cmdu_cstruct *)calloc(1,
sizeof(struct cmdu_cstruct));
- if (!cmdu_data) {
+ if (!cmdu) {
fprintf(stderr, "Out of memory!\n");
return -1;
}
- cmdu_data->message_type = CMDU_AP_CAPABILITY_REPORT;
- memcpy(cmdu_data->origin, rec_cmdu->origin, 6);
- cmdu_data->message_id = rec_cmdu->message_id;
- strcpy(cmdu_data->intf_name, rec_cmdu->intf_name);
+ cmdu->message_type = CMDU_AP_CAPABILITY_REPORT;
+ memcpy(cmdu->origin, rec_cmdu->origin, 6);
+ cmdu->message_id = rec_cmdu->message_id;
- cmdu_data->num_tlvs = 3 * a->num_radios + 1; /* (Radio basic, HT, VHT capability per radio) */
- cmdu_data->tlvs = (uint8_t **)calloc(cmdu_data->num_tlvs,
+ cmdu->num_tlvs = 3 * a->num_radios + 1; /* (Radio basic, HT, VHT capability per radio) */
+ cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
sizeof(uint8_t *));
- if (!cmdu_data->tlvs) {
- map_free_cmdu(cmdu_data);
+ if (!cmdu->tlvs) {
+ map_free_cmdu(cmdu);
return -1;
}
/* AP basic Radio Capability TLV*/
for (j = 0; j < a->num_radios; j++) {
- struct tlv_ap_radio_basic_cap *p =
- (struct tlv_ap_radio_basic_cap *)calloc(1,
- sizeof(struct tlv_ap_radio_basic_cap));
- if (p) {
- p->tlv_type = MAP_TLV_AP_RADIO_BASIC_CAPABILITIES;
- get_ap_radio_basic_cap(a, p, j);
- cmdu_data->tlvs[tlv_index++] = (uint8_t *)p;
- }
+ struct tlv_ap_radio_basic_cap *p;
+
+ p = agent_gen_ap_radio_basic_cap(a, cmdu, j);
+ if (!p)
+ continue;
+ //cmdu->num_tlvs++;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p;
}
/* Collection Interval TLV*/
/* struct tlv_metric_collection_interval *p1 =
@@ -405,52 +648,52 @@ int handle_ap_caps_query(void *agent, struct cmdu_cstruct *rec_cmdu)
* if (p1) {
* p1->tlv_type = MAP_TLV_METRIC_COLLECTION_INTERVAL;
* get_collection_interval(a, p1);
- * cmdu_data->tlvs[tlv_index++] = (uint8_t *)p1;
+ * cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
* }
*/
/* AP capability TLV */
- struct tlv_ap_cap *p2 = (struct tlv_ap_cap *)calloc(1,
- sizeof(struct tlv_ap_cap));
- if (p2) {
- p2->tlv_type = MAP_TLV_AP_CAPABILITY;
- p2->op_ch_metric_reporting = 0;
- p2->non_op_ch_metric_reporting = 0;
- p2->agent_init_rcpi_steering = 0;
- cmdu_data->tlvs[tlv_index++] = (uint8_t *)p2;
- }
+ p2 = agent_gen_ap_caps(a, cmdu);
+ if (!p2)
+ return -1;
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+ //cmdu->num_tlvs++;
/* HT Capability */
for (j = 0; j < a->num_radios; j++) {
- struct tlv_ap_ht_cap *p3 = (struct tlv_ap_ht_cap *)calloc(1,
- sizeof(struct tlv_ap_ht_cap));
- if (p3) {
- p3->tlv_type = MAP_TLV_AP_HT_CAPABILITIES;
- get_ap_ht_caps(a, p3, j);
- cmdu_data->tlvs[tlv_index++] = (uint8_t *)p3;
- }
+ struct tlv_ap_ht_cap *p3;
+
+ p3 = agent_gen_ap_ht_caps(a, cmdu, j);
+ if (!p3)
+ continue;
+ //cmdu->num_tlvs++;
+
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p3;
}
/*VHT Capability */
for (j = 0; j < a->num_radios; j++) {
- struct tlv_ap_vht_cap *p4 = (struct tlv_ap_vht_cap *)calloc(1,
- sizeof(struct tlv_ap_vht_cap));
- if (p4) {
- p4->tlv_type = MAP_TLV_AP_VHT_CAPABILITIES;
- get_ap_vht_caps(a, p4, j);
- cmdu_data->tlvs[tlv_index++] = (uint8_t *)p4;
- }
+ struct tlv_ap_vht_cap *p4;
+
+ p4 = agent_gen_ap_vht_caps(a, cmdu, j);
+ if (!p4)
+ continue;
+ //cmdu->num_tlvs++;
+
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p4;
}
- ret = agent_send_cmdu(a, cmdu_data);
- map_free_cmdu(cmdu_data);
+ ret = agent_send_cmdu(a, cmdu);
+ map_free_cmdu(cmdu);
return ret;
}
int handle_map_policy_config(void *agent, struct cmdu_cstruct *cmdu)
{
- struct tlv *t;
+ //struct tlv *t;
trace("%s: --->\n", __func__);
@@ -945,8 +1188,8 @@ static const map_cmdu_handler_t i1905ftable[] = {
[0x02] = handle_topology_query,
[0x03] = handle_topology_response,
/* hole */
- [0x07] = handle_ap_autoconfig_search,
- /* [0x08] = handle_ap_autoconfig_response, */
+ /* [0x07] = handle_ap_autoconfig_search, */
+ [0x08] = handle_ap_autoconfig_response,
[0x09] = handle_ap_autoconfig_wsc,
};
@@ -1149,14 +1392,14 @@ int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu)
struct blob_buf b = { 0 };
char dst_addr[18] = { 0 };
char *tlv_str = NULL;
- uint8_t is_store_mid = 1;
uint8_t *ss = NULL;
uint16_t msgid = 0;
uint16_t len;
int ret = 0;
size_t i;
uint32_t id;
- struct ieee1905_cmdu_msg *cmsg = NULL;
+ //uint8_t is_store_mid = 1;
+ //struct ieee1905_cmdu_msg *cmsg = NULL;
trace("|%s:%d| Entry\n", __func__, __LINE__);
@@ -1249,7 +1492,7 @@ int agent_handle_map_event(struct agent *a, uint16_t cmdutype, uint16_t mid,
char *rxif, uint8_t *src, uint8_t *tlvs, int len)
{
const map_cmdu_handler_t *f;
- struct cmdu_cstruct *cmdu;
+ struct cmdu_cstruct *cmdu = NULL;
int ret = -1;
int idx;
@@ -1270,7 +1513,7 @@ int agent_handle_map_event(struct agent *a, uint16_t cmdutype, uint16_t mid,
ret = f[idx](a, cmdu);
map_free_cmdu(cmdu);
} else {
- dbg("%s: map_build_cmdu() failed!\n");
+ dbg("agent: %s: map_build_cmdu() failed!\n", __func__);
}
}
diff --git a/src/core/agent_map.h b/src/core/agent_map.h
index fbb4881c7550eb13e80730de2b042b3dece44f67..a2f9b30d3ae0d02e0232f8335e069935df2c133f 100644
--- a/src/core/agent_map.h
+++ b/src/core/agent_map.h
@@ -8,8 +8,11 @@ extern bool is_cmdu_for_us(struct agent *a, uint16_t type);
extern int agent_handle_map_cmd(struct agent *a, char *data, int len);
extern int agent_handle_map_event(struct agent *a, uint16_t cmdutype,
- uint16_t mid, char *rxif, uint8_t *src,
- uint8_t *tlvs, int len);
+ uint16_t mid, char *rxif, uint8_t *src,
+ uint8_t *tlvs, int len);
+int build_ap_autoconfig_wsc(void *agent, uint8_t *hwaddr,
+ struct wifi_radio_element *radio, int idx);
+int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu);
#endif /* AGENT_MAP_H */
diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c
new file mode 100644
index 0000000000000000000000000000000000000000..dfa28546b5816995d4c0aff716ebb5917354b7db
--- /dev/null
+++ b/src/core/agent_tlv_generator.c
@@ -0,0 +1,252 @@
+/*
+ * agent_tlv_generator.c - tlv building function
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <pthread.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#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 <map1905/map2.h>
+#include <map1905/maputils.h>
+#include <wsc.h>
+
+#include "map_module.h"
+#include "utils.h"
+#include "debug.h"
+#include "liblist.h"
+#include "steer_rules.h"
+#include "config.h"
+#include "comm.h"
+#include "msgqueue.h"
+#include "worker.h"
+#include "agent.h"
+//#include "platform_interfaces.h"
+#include "agent_tlv_generator.h"
+
+struct tlv_ap_ht_cap *agent_gen_ap_ht_caps(struct agent *a,
+ struct cmdu_cstruct *cmdu, uint32_t radio_index)
+{
+ struct tlv_ap_ht_cap *p;
+ struct wifi_radio_element *radio;
+ struct netif_fh *fh;
+
+ radio = a->radios + radio_index;
+
+ p = (struct tlv_ap_ht_cap *)calloc(1,
+ sizeof(struct tlv_ap_ht_cap));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_AP_HT_CAPABILITIES;
+
+ fh = wifi_radio_to_ap(a, radio->name);
+ if (!fh) {
+ free(p);
+ return NULL;
+ }
+
+ memcpy(p->radio_id, radio->macaddr, 6);
+ p->max_tx_streams_supported = (radio->tx_streams - 1) & 0xff;
+ p->max_rx_streams_supported = (radio->rx_streams - 1) & 0xff;
+ p->gi_20_support = fh->caps.ht & (1 << 3) ? 1 : 0;
+ p->gi_40_support = fh->caps.ht & (1 << 2) ? 1 : 0;
+ p->ht_40_support = fh->caps.ht & (1 << 1) ? 1 : 0;
+
+ return p;
+}
+
+struct tlv_ap_cap *agent_gen_ap_caps(struct agent *a,
+ struct cmdu_cstruct *cmdu)
+{
+ struct tlv_ap_cap *p;
+
+ p = (struct tlv_ap_cap *)calloc(1,
+ sizeof(struct tlv_ap_cap));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_AP_CAPABILITY;
+ p->op_ch_metric_reporting = 0;
+ p->non_op_ch_metric_reporting = 0;
+ p->agent_init_rcpi_steering = 0;
+
+ return p;
+}
+
+struct tlv_ap_radio_basic_cap *agent_gen_ap_radio_basic_cap(struct agent *a,
+ struct cmdu_cstruct *cmdu, uint32_t radio_index)
+{
+ uint32_t j;
+ struct wifi_radio_element *radio;
+ struct tlv_ap_radio_basic_cap *p;
+
+ radio = a->radios + radio_index;
+
+ p = (struct tlv_ap_radio_basic_cap *)calloc(1,
+ sizeof(struct tlv_ap_radio_basic_cap));
+
+ p->tlv_type = MAP_TLV_AP_RADIO_BASIC_CAPABILITIES;
+ memcpy(p->radio_id, radio->macaddr, 6);
+ p->max_bss_nr = 4; // Max BSS per Radio
+ p->operating_classes_nr = radio->num_supp_opclass;
+
+ if (p->operating_classes_nr > 0)
+ p->operating_class = calloc(p->operating_classes_nr,
+ sizeof(*p->operating_class));
+ if (!p->operating_class) {
+ fprintf(stderr, "|%s:%d| out of memory!\n", __func__, __LINE__);
+ p->operating_classes_nr = 0;
+ return p;
+ }
+
+ for (j = 0; j < p->operating_classes_nr; j++) {
+ p->operating_class[j].op_class = radio->supp_opclass[j].id;
+ p->operating_class[j].max_tx_power = radio->supp_opclass[j].max_txpower;
+ p->operating_class[j].non_op_ch_nr = radio->supp_opclass[j].num_exclude_channels;
+ if (p->operating_class[j].non_op_ch_nr > 0) {
+ p->operating_class[j].channel =
+ (uint8_t *)calloc(p->operating_class[j].non_op_ch_nr,
+ sizeof(uint8_t));
+ if (p->operating_class[j].channel) {
+ memcpy(p->operating_class[j].channel, radio->supp_opclass[j].exclude_chanlist,
+ p->operating_class[j].non_op_ch_nr);
+ }
+ }
+ }
+
+ return p;
+}
+
+struct tlv_ap_vht_cap *agent_gen_ap_vht_caps(struct agent *a,
+ struct cmdu_cstruct *cmdu, uint32_t radio_index)
+{
+ struct tlv_ap_vht_cap *p;
+ struct wifi_radio_element *radio;
+ struct netif_fh *fh;
+
+ radio = a->radios + radio_index;
+
+ fh = wifi_radio_to_ap(a, radio->name);
+ if (!fh)
+ return NULL;
+
+ p = (struct tlv_ap_vht_cap *)calloc(1,
+ sizeof(struct tlv_ap_vht_cap));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_AP_VHT_CAPABILITIES;
+ memcpy(p->radio_id, radio->macaddr, 6);
+ memcpy(&p->vht_tx_mcs_supported, &fh->caps.mcs.vht_mcs_txmap, 2);
+ memcpy(&p->vht_rx_mcs_supported, &fh->caps.mcs.vht_mcs_rxmap, 2);
+ p->max_tx_streams_supported = (fh->tx_spatial_streams - 1);
+ p->max_rx_streams_supported = (fh->rx_spatial_streams - 1);
+ p->gi_80_support = fh->caps.vht[4] & (1 << 1) ? 1 : 0;
+ p->gi_160_support = fh->caps.vht[4] & (1 << 0) ? 1 : 0;
+ p->vht_8080_support = fh->caps.vht[5] & (1 << 7) ? 1 : 0;
+ p->vht_160_support = fh->caps.vht[5] & (1 << 6) ? 1 : 0;
+ p->su_beamformer_capable = fh->caps.vht[5] & (1 << 5) ? 1 : 0;
+ p->mu_beamformer_capable = fh->caps.vht[5] & (1 << 4) ? 1 : 0;
+
+ return p;
+}
+
+struct tlv_profile2_ap_cap *agent_gen_profile2_ap_cap(struct agent *a,
+ struct cmdu_cstruct *cmdu)
+{
+ struct tlv_profile2_ap_cap *p;
+
+ p = (struct tlv_profile2_ap_cap *)calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_PROFILE2_AP_CAPABILITY;
+ p->byte_counter = 0;
+ p->max_vids = (uint8_t)255;
+
+ return p;
+}
+
+struct tlv_ap_radio_adv_cap *agent_gen_ap_radio_adv_cap(struct agent *a,
+ struct cmdu_cstruct *cmdu, struct wifi_radio_element *radio)
+{
+ struct tlv_ap_radio_adv_cap *p;
+
+ p = (struct tlv_ap_radio_adv_cap *) calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = MAP_TLV_AP_RADIO_ADV_CAPABILITY;
+ memcpy(p->radio_id, radio->macaddr, 6);
+ p->combined_front_back = 0;
+ p->combined_p1_p2 = (a->cfg.profile == 0x02);
+
+ return p;
+}
+
+struct tlv_wsc *agent_gen_wsc(struct agent *a, struct cmdu_cstruct *cmdu,
+ struct wifi_radio_element *radio)
+{
+ struct tlv_wsc *p;
+ struct wsc_key *key;
+ int rv;
+ uint16_t len = 0;
+
+ p = (struct tlv_wsc *) calloc(1, sizeof(*p));
+ if (!p)
+ return NULL;
+
+ p->tlv_type = TLV_TYPE_WSC;
+
+ // TODO: auth_type uses dummy value (WPA2PSK)
+ // TODO: remove iface name from wscbuildm1 lib func
+ rv = wscBuildM1(radio->name, &p->wsc_frame, &len, &key, a->al_mac,
+ radio->band, 0x0020, 0);
+ if (!rv)
+ goto fail_p;
+
+ p->wsc_frame_size = len;
+ radio->autconfig.m1_size = len;
+
+ // discard previous frame if it has not been used
+ if (radio->autconfig.m1_frame)
+ free(radio->autconfig.m1_frame);
+ radio->autconfig.m1_frame = calloc(1, len);
+ if (!radio->autconfig.m1_frame)
+ goto fail_key;
+
+ memcpy(radio->autconfig.m1_frame, p->wsc_frame, len);
+ // discard previous key if it has not been used
+ if (radio->autconfig.key) {
+ free(radio->autconfig.key->key);
+ free(radio->autconfig.key);
+ }
+ radio->autconfig.key = key;
+
+ return p;
+fail_key:
+ free(key);
+fail_p:
+ map_free_tlv_cstruct((uint8_t *) p);
+ return NULL;
+}
\ No newline at end of file
diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c400bfdbc9fc003c4daac32db13e3713ea16a50
--- /dev/null
+++ b/src/core/agent_tlv_generator.h
@@ -0,0 +1,27 @@
+/*
+ * agent_tlv_generator.h - tlv building function declarations
+ *
+ * Copyright (C) 2020 IOPSYS Software Solutions AB. All rights reserved.
+ *
+ * Author: jakob.olsson@iopsys.eu
+ *
+ */
+
+#ifndef CNTLR_TLV_GEN_H
+#define CNTLR_TLV_GEN_H
+
+struct tlv_ap_ht_cap *agent_gen_ap_ht_caps(struct agent *a,
+ struct cmdu_cstruct *cmdu, uint32_t radio_index);
+struct tlv_ap_cap *agent_gen_ap_caps(struct agent *a,
+ struct cmdu_cstruct *cmdu);
+struct tlv_ap_radio_basic_cap *agent_gen_ap_radio_basic_cap(struct agent *a,
+ struct cmdu_cstruct *cmdu, uint32_t radio_index);
+struct tlv_ap_vht_cap *agent_gen_ap_vht_caps(struct agent *a,
+ struct cmdu_cstruct *cmdu, uint32_t radio_index);
+struct tlv_profile2_ap_cap *agent_gen_profile2_ap_cap(struct agent *a,
+ struct cmdu_cstruct *cmdu);
+struct tlv_ap_radio_adv_cap *agent_gen_ap_radio_adv_cap(struct agent *a,
+ struct cmdu_cstruct *cmdu, struct wifi_radio_element *radio);
+struct tlv_wsc *agent_gen_wsc(struct agent *a, struct cmdu_cstruct *cmdu,
+ struct wifi_radio_element *radio);
+#endif
diff --git a/src/core/agent_ubus.c b/src/core/agent_ubus.c
index f36af1f56a4cdfb863f03f4cb6c168d01b6c76ee..c1e9c75ee5b095dbc123c0fe5636c69a28ffa789 100644
--- a/src/core/agent_ubus.c
+++ b/src/core/agent_ubus.c
@@ -16,6 +16,8 @@
#include <libubus.h>
#include <uci.h>
+#include <map1905/map2.h>
+#include <map1905/maputils.h>
#include <easy/easy.h>
#include <wifi.h>
@@ -92,7 +94,6 @@ static const struct blobmsg_policy cmd_params[_CMD_MAX] = {
[CMD_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING },
};
-
enum {
CFG_POLICY_AGENT,
CFG_POLICY_BSSID,
@@ -104,6 +105,17 @@ static const struct blobmsg_policy config_policy_params[__CFG_POLICY_MAX] = {
[CFG_POLICY_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING },
};
+enum {
+ SEARCH_POLICY_AGENT,
+ SEARCH_POLICY_EGRESS,
+ __SEARCH_POLICY_MAX,
+};
+
+static const struct blobmsg_policy search_policy_params[__SEARCH_POLICY_MAX] = {
+ [SEARCH_POLICY_AGENT] = { .name = "agent", .type = BLOBMSG_TYPE_STRING },
+ [SEARCH_POLICY_EGRESS] = { .name = "egress", .type = BLOBMSG_TYPE_STRING }
+};
+
static int steer_policy(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
@@ -363,13 +375,9 @@ static int agent_config_ap(struct ubus_context *ctx, struct ubus_object *obj,
struct agent *a = container_of(obj, struct agent, obj);
struct blob_attr *tb[__CFG_POLICY_MAX];
char agent[18] = {0}, bssidstr[18] = {0};
-
+ struct wifi_radio_element *radio, *found = NULL;
uint8_t hwaddr[6] = {0}, bssid[6] = {0};
- struct cmdu_cstruct *cmdu;
- struct tlv_ap_radio_identifier *p = NULL;
- struct tlv_default_8021q_settings *p1;
- struct tlv_traffic_sep_policy *p2;
- int i, tlv_index = 0;
+ int i;
blobmsg_parse(config_policy_params, __CFG_POLICY_MAX, tb,
blob_data(msg), blob_len(msg));
@@ -389,26 +397,121 @@ static int agent_config_ap(struct ubus_context *ctx, struct ubus_object *obj,
if (!hwaddr_aton(bssidstr, bssid))
return UBUS_STATUS_UNKNOWN_ERROR;
- build_ap_autoconfig_wsc(a, hwaddr, bssid);
+ for (i = 0; i < a->num_radios; i++) {
+ radio = a->radios + i;
- /*
- else if (tb[CFG_POLICY_RADIO]) {
- char radio[18] = {0};
- struct netif_radio *r;
+ if (memcmp(radio->macaddr, bssid, 6))
+ continue;
+ found = radio;
+ }
+ if (!found)
+ return UBUS_STATUS_UNKNOWN_ERROR;
- strncpy(radio, blobmsg_data(tb[CFG_POLICY_RADIO]),
- sizeof(radio) - 1);
- r = cntlr_radio_to_bssid(c, radio);
- if (!r) {
- free(cmdu);
- return UBUS_STATUS_UNKNOWN_ERROR;
- }
+ build_ap_autoconfig_wsc(a, hwaddr, radio, i);
+
+ return 0;
+}
+
+
+static int agent_ap_search(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ struct agent *a = container_of(obj, struct agent, obj);
+ struct blob_attr *tb[__SEARCH_POLICY_MAX];
+ struct cmdu_cstruct *cmdu;
+ struct tlv_supp_service *p = NULL;
+ struct tlv_searched_service *p1;
+ struct tlv_map_profile *p2;
+ int i, tlv_index = 0;
+
+ blobmsg_parse(config_policy_params, __SEARCH_POLICY_MAX, tb,
+ blob_data(msg), blob_len(msg));
+
+ // TODO: ff:ff:ff:ff:ff:ff = send to all agents
+ cmdu = (struct cmdu_cstruct *)calloc(1, sizeof(struct cmdu_cstruct));
+ if (!cmdu) {
+ fprintf(stderr, "failed to malloc cmdu\n");
+ return UBUS_STATUS_UNKNOWN_ERROR;
+ }
- p = cntlr_gen_config_ap_tlv(c, cmdu, r->hwaddr);
+ if (tb[SEARCH_POLICY_AGENT]) {
+ char agent[18] = {0};
+
+ strncpy(agent, blobmsg_data(tb[SEARCH_POLICY_AGENT]),
+ sizeof(agent) - 1);
+ if (!hwaddr_aton(agent, cmdu->origin))
+ return UBUS_STATUS_UNKNOWN_ERROR;
}
- */
+ if (tb[SEARCH_POLICY_EGRESS])
+ strncpy(cmdu->intf_name, blobmsg_data(tb[SEARCH_POLICY_EGRESS]),
+ sizeof(cmdu->intf_name) - 1);
+ else
+ strncpy(cmdu->intf_name, "br-lan", sizeof(cmdu->intf_name) - 1);
+
+ cmdu->message_type = CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH;
+
+ p = calloc(1, sizeof(struct tlv_supp_service));
+ if (!p)
+ goto fail_cmdu;
+
+ cmdu->num_tlvs++;
+ p->tlv_type = MAP_TLV_SUPPORTED_SERVICE;
+ p->supported_services_list = 1;
+ p->supported_services = calloc(p->supported_services_list,
+ sizeof(*p->supported_services));
+ if (!p->supported_services)
+ goto fail_p;
+
+ for (i = 0; i < p->supported_services_list; i++)
+ p->supported_services[i].service = SUPPORTED_SERVICE_MULTIAP_AGENT;
+
+ p1 = calloc(1, sizeof(struct tlv_searched_service));
+ if (!p1)
+ goto fail_p;
+
+ cmdu->num_tlvs++;
+ p1->tlv_type = MAP_TLV_SEARCHED_SERVICE;
+ p1->searched_services_list = 1;
+ p1->service = calloc(p1->searched_services_list, sizeof(*p1->service));
+ if (!p1->service)
+ goto fail_p1;
+
+ for (i = 0; i < p->supported_services_list; i++)
+ p->supported_services[i].service = SEARCHED_SERVICE_MULTIAP_CONTROLLER;
+
+ p2 = calloc(1, sizeof(struct tlv_map_profile));
+ if (!p2)
+ goto fail_p1;
+
+ cmdu->num_tlvs++;
+ p2->tlv_type = MAP_TLV_MULTIAP_PROFILE;
+ p2->profile = 0x02;
+
+ cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs,
+ sizeof(uint8_t *));
+
+ if (!cmdu->tlvs)
+ goto fail_p2;
+
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p;
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p1;
+ cmdu->tlvs[tlv_index++] = (uint8_t *)p2;
+
+ agent_send_cmdu(a, cmdu);
+ map_free_cmdu(cmdu);
return 0;
+
+fail_p2:
+ map_free_tlv_cstruct((uint8_t *) p2);
+fail_p1:
+ map_free_tlv_cstruct((uint8_t *) p1);
+fail_p:
+ map_free_tlv_cstruct((uint8_t *) p);
+fail_cmdu:
+ free(cmdu);
+ return UBUS_STATUS_UNKNOWN_ERROR;
}
int agent_publish_object(struct agent *a, const char *objname)
@@ -416,7 +519,8 @@ int agent_publish_object(struct agent *a, const char *objname)
struct ubus_object *obj;
struct ubus_object_type *obj_type;
struct ubus_method *obj_methods;
- struct ubus_method m[7] = {
+ struct ubus_method m[8] = {
+ UBUS_METHOD("ap_search", agent_ap_search, search_policy_params),
UBUS_METHOD("config_ap", agent_config_ap, config_policy_params),
UBUS_METHOD("steer_policy", steer_policy, steer_policy_params),
UBUS_METHOD("steer", steer, steer_params),
@@ -505,8 +609,11 @@ int agent_publish_object(struct agent *a, const char *objname)
void agent_remove_object(struct agent *a)
{
- if (a->ubus_ctx && a->obj.id != OBJECT_INVALID)
+ if (a->ubus_ctx && a->obj.id != OBJECT_INVALID) {
ubus_remove_object(a->ubus_ctx, &a->obj);
+ free(a->obj.type);
+ free((void *) a->obj.methods);
+ }
}
/*
diff --git a/src/core/config.c b/src/core/config.c
index c95fbe3908b7551ff2f58ce890a7f132f105eeac..a9c229fac82753dd428b8ad57e1478f534e2ba5a 100644
--- a/src/core/config.c
+++ b/src/core/config.c
@@ -32,6 +32,25 @@
#include "worker.h"
#include "agent.h"
+#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 WPS_ENCR_NONE (0x0001)
+#define WPS_ENCR_WEP (0x0002) /* deprecated */
+#define WPS_ENCR_TKIP (0x0004)
+#define WPS_ENCR_AES (0x0008)
+
+// UCI sections
+#define UCI_BK_AGENT "bk-iface"
+#define UCI_FH_AGENT "fh-iface"
+#define UCI_WLAN_IFACE "wifi-iface"
+#define UCI_WIRELESS "wireless"
+#define UCI_IEEE1905 "ieee1905"
+#define UCI_AGENT "agent"
+
int verbose;
static int set_value(struct uci_context *ctx, struct uci_package *pkg,
@@ -54,8 +73,8 @@ static int set_value(struct uci_context *ctx, struct uci_package *pkg,
return -1;
}
-static struct uci_section *wifi_get_iface_section(struct uci_context *ctx,
- struct uci_package *pkg, char *ifname)
+static struct uci_section *config_get_iface_section(struct uci_context *ctx,
+ struct uci_package *pkg, const char *type, const char *ifname)
{
struct uci_element *e;
@@ -66,7 +85,7 @@ static struct uci_section *wifi_get_iface_section(struct uci_context *ctx,
const char *c_ifname;
section = uci_to_section(e);
- if (strcmp(section->type, "wifi-iface"))
+ if (strcmp(section->type, type))
continue;
c_ifname = uci_lookup_option_string(ctx, section, "ifname");
@@ -77,12 +96,45 @@ static struct uci_section *wifi_get_iface_section(struct uci_context *ctx,
return NULL;
}
+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_iface_section(ctx, pkg, type, 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_element *e;
struct uci_section *section;
int rv = -1;
@@ -95,7 +147,7 @@ int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
goto out_uci;
}
- section = wifi_get_iface_section(ctx, pkg, ifname);
+ section = config_get_iface_section(ctx, pkg, "wifi-iface", ifname);
if (!section)
goto out_pkg;
@@ -113,8 +165,468 @@ out:
return rv;
}
+int config_add_section(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 '%s' not found!\n", config);
+ goto out_uci;
+ }
+
+ section = config_get_iface_section(ctx, pkg, type, ifname);
+ if (section)
+ goto out_pkg;
+
+ 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 = ifname;
+ ptr.package = config;
+ ptr.section = section->e.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);
+out_pkg:
+ uci_unload(ctx, pkg);
+out_uci:
+ uci_free_context(ctx);
+out:
+ return rv;
+}
+
+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;
+
+ rv = config_add_section(config, type, ifname);
+ if (rv)
+ return -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_iface_section(ctx, pkg, type, ifname);
+ if (!section)
+ goto out_pkg;
+
+ 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 rv;
+}
+
+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;
+
+ rv = config_add_section(config, type, ifname);
+ if (rv)
+ return -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_iface_section(ctx, pkg, type, ifname);
+ if (!section)
+ goto out_pkg;
+
+ 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 rv;
+}
+
+/* below functions are mostly taken from ieee1905d */
+static 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;
+}
+
+static bool uci_set_wireless_interface_option(char *package_name,
+ char *section_type, char *ifname, char *option, char *value)
+{
+ struct uci_context *ctx;
+ struct uci_package *pkg;
+ struct uci_element *e;
+
+ if (!package_name || !ifname || !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,
+ "ifname");
+
+ if (!opt || opt->type != UCI_TYPE_STRING)
+ continue;
+ if (strcmp(opt->v.string, ifname) == 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
+ 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;
+}
+
+static bool uci_add_wireless_iface_sec(char *package_name, char *interface_name,
+ char *section_name)
+{
+ struct uci_context *ctx;
+ struct uci_package *pkg;
+ struct uci_section *s;
+
+ if (!interface_name || !package_name)
+ return false;
+
+ ctx = uci_alloc_context();
+ if (!ctx)
+ return false;
+
+ if (uci_load(ctx, package_name, &pkg)) {
+ uci_free_context(ctx);
+ return false;
+ }
+
+ if (uci_add_section(ctx, pkg, section_name, &s) == UCI_OK) {
+ struct uci_ptr ptr = {0};
+
+ if (uci_save(ctx, pkg) != UCI_OK)
+ return false;
+
+ ptr.value = interface_name;
+ ptr.package = package_name;
+ ptr.section = s->e.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);
+ }
+
+ uci_unload(ctx, pkg);
+ uci_free_context(ctx);
+
+ return true;
+}
+
+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;
+}
+
+static bool uci_reload_services(void)
+{
+ struct blob_buf bb;
+
+ memset(&bb, 0, sizeof(struct blob_buf));
+ blob_buf_init(&bb, 0);
+
+ info("## Reloading uci config\n");
+ if (!ubus_call("uci", "reload_config", &bb, NULL, NULL))
+ return true;
+
+ blob_buf_free(&bb);
+
+ return false;
+}
+
+int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
+ uint16_t auth_type, uint16_t encryption_type,
+ uint8_t *network_key, uint8_t mapie, uint8_t band)
+{
+ bool ret;
+ char auth_type_str[20] = {0};
+ char multiap_str[2] = {0};
+ uint8_t multi_ap = 0;
+ bool sta_mode;
+ char band_str[2] = {0};
+
+ dbg("Applying WSC configuration (%s):\n", interface_name);
+ dbg(" - SSID : %s\n", ssid);
+ dbg(" - BSSID : %02x:%02x:%02x:%02x:%02x:%02x\n",
+ bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+ dbg(" - AUTH_TYPE : 0x%04x\n", auth_type);
+ dbg(" - ENCRYPTION_TYPE : 0x%04x\n", encryption_type);
+ dbg(" - NETWORK_KEY : %s\n", network_key);
+ dbg(" - MAPIE_EXTENSION : 0x%02x\n", mapie);
+
+ // if teardown bit is set, return
+ if (BIT(3, mapie))
+ return M2_PROCESS_TEARDOWN;
+
+ multi_ap |= (BIT(5, mapie) << 1);
+ multi_ap |= BIT(6, mapie);
+ sta_mode = BIT(7, mapie);
+
+ snprintf(multiap_str, sizeof(multiap_str), "%d", multi_ap);
+
+ if (!get_encryption_value(auth_type, encryption_type,
+ auth_type_str, 20)) {
+ info("Unsupported encryption or cipher received!!\n");
+ return M2_PROCESS_ERROR;
+ }
+
+ // Set uci in agent
+ ret = uci_check_wifi_iface(UCI_AGENT, interface_name,
+ (sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT));
+ if (!ret) {
+ ret = uci_add_wireless_iface_sec(UCI_AGENT, interface_name,
+ (sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT));
+ if (!ret)
+ return M2_PROCESS_ERROR;
+ }
+
+ printf("%s band = %d\n", __func__, band);
+
+ if (band == BAND_5)
+ strncpy(band_str, "5", 1);
+ else if (band == BAND_2)
+ strncpy(band_str, "2", 1);
+ else /* TODO: 60 */
+ return M2_PROCESS_ERROR;
+
+ uci_set_wireless_interface_option(UCI_AGENT,
+ (sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT),
+ interface_name, "band",
+ band_str);
+ if (sta_mode) {
+ char disallow_str[2] = {0};
+
+ snprintf(disallow_str, sizeof(disallow_str), "%d",
+ ((mapie >> 2) & 0x03));
+ uci_set_wireless_interface_option(UCI_AGENT,
+ (sta_mode ? UCI_BK_AGENT : UCI_FH_AGENT),
+ interface_name,
+ "disallow_bsta", disallow_str);
+ }
+
+ // Set uci in ieee1905
+ ret = uci_check_wifi_iface(UCI_IEEE1905, interface_name,
+ UCI_WLAN_IFACE);
+ if (!ret) {
+ ret = uci_add_wireless_iface_sec(UCI_IEEE1905, interface_name,
+ UCI_WLAN_IFACE);
+ if (!ret)
+ return M2_PROCESS_ERROR;
+ }
+
+ uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+ interface_name, "ssid", (char *) ssid);
+ uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+ interface_name, "key", (char *) network_key);
+ uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+ interface_name, "encryption", auth_type_str);
+ uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+ interface_name, "multi_ap", multiap_str);
+ uci_set_wireless_interface_option(UCI_IEEE1905, UCI_WLAN_IFACE,
+ interface_name, "mode", (sta_mode ? "sta" : "ap"));
+
+ // Set uci in wireless
+ ret = uci_check_wifi_iface(UCI_WIRELESS, interface_name,
+ UCI_WLAN_IFACE);
+ if (!ret) {
+ ret = uci_add_wireless_iface_sec(UCI_WIRELESS, interface_name,
+ UCI_WLAN_IFACE);
+ if (!ret)
+ return M2_PROCESS_ERROR;
+ }
+
+ uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+ interface_name, "ssid", (char *) ssid);
+ uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+ interface_name, "key", (char *) network_key);
+ uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+ interface_name, "encryption", auth_type_str);
+ uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+ interface_name, "multi_ap", multiap_str);
+ uci_set_wireless_interface_option(UCI_WIRELESS, UCI_WLAN_IFACE,
+ interface_name, "mode", (sta_mode ? "sta" : "ap"));
+
+ uci_reload_services();
+ 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)
+ const char *name)
{
struct netif_bkcfg *p;
@@ -179,6 +691,29 @@ void stax_del_entry(struct list_head *h, char *sta_macstr)
}
}
+static int clean_steer_btm_excl(struct netif_fhcfg *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 netif_fhcfg *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;
@@ -314,6 +849,7 @@ struct netif_fhcfg *create_fronthaul_iface_config(struct agent_config *cfg,
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) {
@@ -352,7 +888,6 @@ struct netif_bkcfg *create_backhaul_iface_config(struct agent_config *cfg,
const char *ifname)
{
struct netif_bkcfg *new;
- struct steer_rule *r;
if (!cfg)
return NULL;
@@ -366,11 +901,12 @@ struct netif_bkcfg *create_backhaul_iface_config(struct agent_config *cfg,
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->fhlist);
+ list_add(&new->list, &cfg->bklist);
return new;
}
@@ -590,7 +1126,7 @@ void register_config(struct config *c)
}
#endif
-static int cntlr_config_get_wifi_agent(struct agent_config *a,
+static int agent_config_get_wifi_agent(struct agent_config *a,
struct uci_section *s)
{
enum {
@@ -623,17 +1159,19 @@ static int cntlr_config_get_wifi_agent(struct agent_config *a,
return 0;
}
-static int cntlr_config_get_bk_iface(struct agent_config *a,
+static int agent_config_get_bk_iface(struct agent_config *a,
struct uci_section *s)
{
enum {
BK_IFNAME,
+ BK_BAND,
BK_ENABLED,
BK_ONBOARDED,
NUM_POLICIES
};
const struct uci_parse_option opts[] = {
{ .name = "ifname", .type = UCI_TYPE_STRING },
+ { .name = "band", .type = UCI_TYPE_STRING },
{ .name = "enabled", .type = UCI_TYPE_STRING },
{ .name = "onboarded", .type = UCI_TYPE_STRING }
};
@@ -667,14 +1205,24 @@ static int cntlr_config_get_bk_iface(struct agent_config *a,
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;
+ }
+
return 0;
}
-static int cntlr_config_get_fh_iface(struct agent_config *a,
+static int agent_config_get_fh_iface(struct agent_config *a,
struct uci_section *s)
{
enum {
FH_IFNAME,
+ FH_BAND,
FH_STEER,
FH_EXCLUDE,
FH_EXCLUDE_BTM,
@@ -689,6 +1237,7 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
};
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 = "exclude", .type = UCI_TYPE_LIST },
{ .name = "exclude_btm", .type = UCI_TYPE_LIST },
@@ -702,12 +1251,14 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
};
struct uci_option *tb[NUM_POLICIES];
struct netif_fhcfg *fh;
- const char *ifname;
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);
@@ -716,6 +1267,8 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
return -1;
}
} else {
+ clean_steer_btm_excl(fh);
+ clean_steer_excl(fh);
warn("Duplicate 'fh-iface %s' config!! ignore\n",
ifname);
}
@@ -724,6 +1277,15 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
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;
@@ -793,8 +1355,8 @@ static int cntlr_config_get_fh_iface(struct agent_config *a,
return 0;
}
-static int cntlr_config_get_steer_param(struct agent_config *a,
- struct uci_section *s)
+static int agent_config_get_steer_param(struct agent_config *a,
+ struct uci_section *s)
{
struct steer_rule *r;
@@ -818,9 +1380,6 @@ int agent_config_reload(struct agent_config *cfg)
cfg->enabled = false;
cfg->runfreq = AGENT_RUN_AUTO;
- INIT_LIST_HEAD(&cfg->fhlist);
- INIT_LIST_HEAD(&cfg->bklist);
-
ctx = uci_alloc_context();
if (!ctx)
return -1;
@@ -834,15 +1393,66 @@ int agent_config_reload(struct agent_config *cfg)
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, "wifiagent"))
- cntlr_config_get_wifi_agent(cfg, s);
+ agent_config_get_wifi_agent(cfg, s);
else if (!strcmp(s->type, "fh-iface"))
- cntlr_config_get_fh_iface(cfg, s);
+ agent_config_get_fh_iface(cfg, s);
else if (!strcmp(s->type, "bk-iface"))
- cntlr_config_get_bk_iface(cfg, s);
+ agent_config_get_bk_iface(cfg, s);
else if (!strcmp(s->type, "steer"))
- cntlr_config_get_steer_param(cfg, s);
+ agent_config_get_steer_param(cfg, s);
}
uci_free_context(ctx);
return 0;
}
+
+int agent_config_init(struct agent_config *cfg)
+{
+ INIT_LIST_HEAD(&cfg->fhlist);
+ INIT_LIST_HEAD(&cfg->bklist);
+
+ 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)
+{
+ clean_steer_btm_excl(p);
+ clean_steer_excl(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;
+}
+
+int agent_config_clean(struct agent_config *cfg)
+{
+ clean_all_fh(cfg);
+ clean_all_bk(cfg);
+
+ return 0;
+}
diff --git a/src/core/config.h b/src/core/config.h
index 211bb9e7424a7b28dfad076e3a6744c51b0cc890..566d2b99ab52dbbf8dedd545fe4bae9e92672709 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -10,6 +10,10 @@
#ifndef CONFIG_H
#define CONFIG_H
+// TODO: try to get rid of these
+#include <easy/easy.h>
+#include <wifi.h>
+
#if 0
enum steer_action {
STEER_DISABLE, /** steer disallowed */
@@ -51,6 +55,7 @@ void stax_del_entry(struct list_head *h, char *sta_macstr);
*/
struct netif_fhcfg {
char name[16];
+ enum wifi_band band;
bool enabled;
bool sta_steer_enabled;
bool assoc_control;
@@ -86,6 +91,7 @@ struct netif_fhcfg {
struct netif_bkcfg {
char name[16];
+ enum wifi_band band;
bool enabled;
bool onboarded;
/* TODO: others as needed */
@@ -121,7 +127,16 @@ union config {
struct agent;
+enum m2_process_status {
+ M2_PROCESS_OK,
+ M2_PROCESS_ERROR,
+ M2_PROCESS_TEARDOWN
+};
+
+
+int agent_config_init(struct agent_config *cfg);
int agent_config_reload(struct agent_config *cfg);
+int agent_config_clean(struct agent_config *cfg);
int agent_config_defaults(struct agent *a, struct agent_config *cfg);
void agent_config_dump(struct agent_config *cfg);
@@ -138,5 +153,18 @@ int config_update2(const char *confname, struct agent_config *cfg,
int wifi_apply_iface_cfg(const char *ifname, const char *encryption,
const char *ssid, const char *key);
-
+int config_del_iface(const char *config, const char *type, const char *ifname);
+int config_add_section(const char *config, const char *type, const char *ifname);
+int config_add_default_wifi_iface(const char *config, const char *type,
+ const char *ifname, const char *device, const char *network,
+ const char *mode);
+
+void clean_bk(struct netif_bkcfg *p);
+int clean_all_bk(struct agent_config *cfg);
+void clean_fh(struct netif_fhcfg *p);
+int clean_all_fh(struct agent_config *cfg);
+
+int uci_apply_m2(char *interface_name, uint8_t *ssid, uint8_t *bssid,
+ uint16_t auth_type, uint16_t encryption_type,
+ uint8_t *network_key, uint8_t mapie, uint8_t band);
#endif
diff --git a/src/utils/debug.c b/src/utils/debug.c
index a95e98d28ab569fe756fe3d4f80d42d87d9c85d7..77291aee5d0b61b67cb0a4a55f011e4fb1737569 100644
--- a/src/utils/debug.c
+++ b/src/utils/debug.c
@@ -221,5 +221,6 @@ void log_cmdu(int level, void *var)
continue;
log_test(level, btlv, len);
+ free(btlv);
}
}
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 3e720ea58eb503e177f66f7759fa96b16ba9ec50..62872845b3cde10d781029505b498b28114107d7 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -91,6 +91,7 @@ char *btostr(unsigned char *bytes, int len, char *str)
for (i = 0; i < len; i++)
sprintf(str + strlen(str), "%02x", bytes[i] & 0xff);
+
return str;
}
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 6b00df0f734eecd8dba6463f76019660f8d97dca..bdde468c60083796cb1c2353f404080f3b441fa1 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -10,6 +10,7 @@
#ifndef UTILS_H
#define UTILS_H
+#include <arpa/inet.h>
#include <time.h>
#include <stdbool.h>
#include <json-c/json.h>
@@ -20,6 +21,7 @@
#define hwaddr_hash(a) (a[0] ^ a[1] ^ a[2] ^ a[3] ^ a[4] ^ a[5])
+#define BIT(m, x) ((x >> m) & 0x0001)
bool match_oui0(unsigned char *oui, unsigned char *hwaddr, int ouis);
unsigned char *hwaddr_aton(const char *macstr, unsigned char *mac);
@@ -47,7 +49,7 @@ unsigned char *strtob(char *str, int len, unsigned char *bytes);
char *btostr(unsigned char *bytes, int len, char *str);
/* utility wrappers over json-c functions */
-int json_get_bool(struct json_object *object, const char *key);
+bool json_get_bool(struct json_object *object, const char *key);
int json_get_int(struct json_object *object, const char *key);
const char *json_get_string(struct json_object *object, const char *key);