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);