diff --git a/src/core/agent.c b/src/core/agent.c index 01ef4051e013d2163ab937ceabd3cd583b602085..345304165b19f58656ca7fdd50662e84f1667ad1 100644 --- a/src/core/agent.c +++ b/src/core/agent.c @@ -1900,7 +1900,7 @@ static void wifi_radio_event_handler(void *c, struct blob_attr *msg) dbg("%s: Unhandled!!! TODO\n", __func__); } -static int wifi_mod_bridge(struct agent *a, char *ifname, char *action) +int wifi_mod_bridge(struct agent *a, char *ifname, char *action) { char bridge[16] = {0}; char cmd[256] = {0}; @@ -1956,6 +1956,11 @@ static int if_setip(const char *name, uint32_t ipaddr) return 0; } +static void agent_detect_loop(struct agent *a, int secs) +{ + uloop_timeout_set(&a->loop_detection_dispatcher, secs * 1000); +} + static void agent_manage_bsta(struct agent *a, char *ifname) { struct ip_address addrs[32] = {0}; @@ -1990,6 +1995,7 @@ static void agent_manage_bsta(struct agent *a, char *ifname) ifname); wifi_mod_bridge(a, ifname, "add"); if_setip(ifname, 0); + agent_detect_loop(a, 2); } } else { if (if_isbridge_interface(ifname)) @@ -2007,6 +2013,19 @@ static void agent_disable_local_cntlr(struct agent *a) uci_reload_services("mapcontroller"); } +static void agent_trigger_vendor_specific(struct uloop_timeout *t) +{ + struct agent *a = container_of(t, struct agent, loop_detection_dispatcher); + struct cmdu_cstruct *cmdu; + uint8_t origin[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x13}; + + cmdu = agent_gen_vendor_specific_cmdu(a, origin, a->depth); + if (cmdu) { + a->loop_detection.tx_mid = agent_send_cmdu(a, cmdu); + map_free_cmdu(cmdu); + } +} + static void ethport_event_handler(void *agent, struct blob_attr *msg) { char ifname[16] = {0}, link[8] = {0}; @@ -2034,6 +2053,9 @@ static void ethport_event_handler(void *agent, struct blob_attr *msg) if (up) { int i; + /* find loop in network */ + agent_detect_loop(a, 1); + /* if is wan port getting a link up, active acs and do cntlr discovery*/ if (!strncmp(a->ethwan, ifname, IFNAMSIZ)) { if (a->cfg.discovery_proto == DISCOVERY_AUTOMATIC) @@ -3855,6 +3877,7 @@ int start_agent(void) ubus_add_uloop(ctx); + w->depth = 2; /* default 2 hops from controller */ agent_config_init(&w->cfg); agent_config_get_ethwan(w->ethwan); memcpy(w->cntlr_almac, w->cfg.cntlr_almac, 6); @@ -3894,13 +3917,14 @@ int start_agent(void) agent_init_interfaces(w); + /* TODO: rename wifi_evh to evh */ ubus_register_event_handler(ctx, &w->wifi_evh, "ethport"); ubus_register_event_handler(ctx, &w->wifi_evh, "wifi.*"); ubus_register_event_handler(ctx, &w->wifi_evh, "wps_credentials"); ubus_register_event_handler(ctx, &w->ieee1905_evh, "ieee1905.*"); w->autocfg_dispatcher.cb = agent_dispatch_autoconfig; - + w->loop_detection_dispatcher.cb = agent_trigger_vendor_specific; w->heartbeat.cb = agent_periodic_run; uloop_timeout_set(&w->heartbeat, 1 * 1000); diff --git a/src/core/agent.h b/src/core/agent.h index f3bceea810efcdb19a6d790497dfc19044d156a7..a0f072b2fded6269c60d2b996c0ff0e2785a453f 100644 --- a/src/core/agent.h +++ b/src/core/agent.h @@ -417,6 +417,7 @@ struct agent { char ethwan[16]; struct uloop_timeout heartbeat; struct uloop_timeout autocfg_dispatcher; + struct uloop_timeout loop_detection_dispatcher; struct list_head fhlist; struct list_head bklist; struct list_head framelist; @@ -442,6 +443,15 @@ struct agent { struct uloop_timeout sta_steer_req_timer; /** steer opportunity timer */ uint32_t sta_steerlist_count; struct wifi_sta_steer_list sta_steer_list[MAX_STA]; + + /* immediate loop detection */ + struct { + time_t rx_time; + uint16_t rx_mid; + uint16_t tx_mid; + } loop_detection; + + uint8_t depth; }; struct netif_bk *find_bkhaul_by_bssid(struct agent *a, uint8_t *bssid); @@ -484,5 +494,6 @@ struct wifi_radio_element *wifi_ifname_to_radio_element(struct agent *a, char *ifname); int prepare_tunneled_message(void *agent, uint8_t protocol, const char *framestr); +int wifi_mod_bridge(struct agent *a, char *ifname, char *action); #endif /* AGENT_H */ diff --git a/src/core/agent_cmdu_generator.c b/src/core/agent_cmdu_generator.c index 5e685b1171fbc9ac3f8ff64d11492366e52e4527..ef69c132a8a9c0cd2870f0c8b59cef86690777ea 100644 --- a/src/core/agent_cmdu_generator.c +++ b/src/core/agent_cmdu_generator.c @@ -653,3 +653,33 @@ error: return NULL; } + + +struct cmdu_cstruct *agent_gen_vendor_specific_cmdu(struct agent *a, + uint8_t *origin, uint8_t depth) +{ + struct tlv_vendor_specific *p; + struct cmdu_cstruct *cmdu; + int tlv_index = 0; + + cmdu = calloc(1, sizeof(struct cmdu_cstruct)); + if (!cmdu) + return NULL; + + cmdu->message_type = CMDU_TYPE_VENDOR_SPECIFIC; + memcpy(cmdu->origin, origin, 6); + strncpy(cmdu->intf_name, a->cfg.al_bridge, IFNAMESIZE - 1); + + p = agent_gen_vendor_specific_tlv(a, depth); + if (!p) + goto error; + + cmdu->num_tlvs++; + cmdu->tlvs = (uint8_t **)calloc(cmdu->num_tlvs, + sizeof(uint8_t *)); + cmdu->tlvs[tlv_index++] = p; + return cmdu; +error: + map_free_cmdu(cmdu); + return NULL; +} diff --git a/src/core/agent_cmdu_generator.h b/src/core/agent_cmdu_generator.h index 2eb4d20eb0577f62f862df64eab2dc90f05ab68c..391be9e6f65f38b886f46033fe7cb25c7774fc8c 100644 --- a/src/core/agent_cmdu_generator.h +++ b/src/core/agent_cmdu_generator.h @@ -21,5 +21,6 @@ struct cmdu_cstruct *agent_gen_assoc_sta_metric_response( struct agent *a, struct cmdu_cstruct *rec_cmdu); struct cmdu_cstruct *agent_gen_tunneled_msg(struct agent *a, uint8_t protocol, uint8_t *sta, int frame_len, uint8_t *frame_body); +struct cmdu_cstruct *agent_gen_vendor_specific_cmdu(struct agent *a, uint8_t *origin, uint8_t depth); #endif diff --git a/src/core/agent_map.c b/src/core/agent_map.c index 7ec72ebfea7e7f619bbb2e465e40a404360d2dac..325d2315b111444d3519302b13ff70d23f8a5db4 100644 --- a/src/core/agent_map.c +++ b/src/core/agent_map.c @@ -89,7 +89,7 @@ struct tlv { typedef int (*map_cmdu_handler_t)(void *agent, struct cmdu_cstruct *cmdu); typedef int (*map_cmdu_sendfunc_t)(void *agent, struct cmdu_cstruct *cmdu); -int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu); +uint16_t agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu); int agent_transition_sta(struct agent *a, struct tlv_steer_Req *p, struct netif_fh *fh, int l, int m); @@ -503,6 +503,24 @@ static const map_cmdu_sendfunc_t agent_maptxftable[] = { [0x33] = send_failed_connection_msg, }; + +int handle_topology_discovery(void *agent, struct cmdu_cstruct *cmdu) +{ + trace("%s: --->\n", __func__); + struct agent *a = (struct agent *) agent; + + if (!memcmp(cmdu->origin, a->cntlr_almac, 6)) { + if (!memcmp(a->cntlr_almac, a->almac, 6)) + a->depth = 0; + else + a->depth = 1; + } + + dbg("|%s:%d| depth %d\n", __func__, __LINE__, a->depth); + + return 0; +} + int handle_topology_notification(void *agent, struct cmdu_cstruct *cmdu) { trace("%s: --->\n", __func__); @@ -521,6 +539,72 @@ int handle_topology_response(void *agent, struct cmdu_cstruct *cmdu) return 0; } + +int handle_vendor_specific(void *agent, struct cmdu_cstruct *rec_cmdu) +{ + trace("%s: --->\n", __func__); + struct agent *a = (struct agent *) agent; + struct tlv_vendor_specific *p; + time_t now; + uint8_t depth = 2; + + time(&now); + p = extract_tlv_by_type(rec_cmdu, TLV_TYPE_VENDOR_SPECIFIC); + if (!p) + return -1; + + trace("|%s:%d| num_tlvs = %d, type = %02x, len = %04x%04x, value = %d\n", __func__, __LINE__, (uint8_t) p->m[0], (uint8_t)p->m[1], (uint16_t)p->m[2], p->m[3], (uint8_t)p->m[4]); + + depth = p->m[4]; + + /* no action if it is not IOPSYS oui */ + if (memcmp(p->vendor_oui, "\x00\x22\x07", 3)) + return -1; + + trace("|%s:%d| iopsys vendor oui CMDU received %02x%02x%02x\n", __func__, __LINE__, p->vendor_oui[0], p->vendor_oui[1], p->vendor_oui[2]); + + /* no action if it is local rec_cmdu */ + if (!memcmp(a->almac, rec_cmdu->origin, 6)) + return -1; + + trace("|%s:%d| rec_cmdu->id = %d, rx_id = %d, tx_id = %d\n", __func__, __LINE__, rec_cmdu->message_id, a->loop_detection.rx_mid, a->loop_detection.tx_mid); + if (rec_cmdu->message_id == a->loop_detection.rx_mid && depth > a->depth) { + trace("|%s:%d| LOOP DETECTED\n", __func__, __LINE__); + if (difftime(now, a->loop_detection.rx_time) < 3) { + trace("|%s:%d| LOOP DETECTED WITHIN TIME FRAME LIMIT OF 3(s)\n", __func__, __LINE__); + struct cmdu_cstruct *cmdu; + + cmdu = agent_gen_vendor_specific_cmdu(a, rec_cmdu->origin, a->depth); + if (cmdu) { + trace("|%s:%d| TRIGGERED LOOP DETECTION RESPONSE\n", __func__, __LINE__); + cmdu->message_id = rec_cmdu->message_id; + agent_send_cmdu(a, cmdu); + map_free_cmdu(cmdu); + } + + } + } else if (rec_cmdu->message_id == a->loop_detection.tx_mid) { + struct netif_bk *bk; + bool reload = false; + + trace("|%s:%d| Received response, loop has been detected! Disable bSTAs\n", __func__, __LINE__); + + list_for_each_entry(bk, &a->bklist, list) { + if (!config_disable_bsta(bk->cfg)) + reload = true; + + wifi_mod_bridge(a, bk->name, "remove"); + } + + if (reload) + uci_reload_services("wireless"); + } + + a->loop_detection.rx_time = now; + a->loop_detection.rx_mid = rec_cmdu->message_id; + return 0; +} + int handle_ap_autoconfig_search(void *agent, struct cmdu_cstruct *cmdu) { trace("agent: %s: --->\n", __func__); @@ -579,6 +663,10 @@ int handle_ap_autoconfig_response(void *agent, struct cmdu_cstruct *cmdu) if (!hwaddr_ntoa(a->cntlr_almac, mac_str)) return -1; + /* set self as root node, used for loop detection */ + if (!memcmp(a->cntlr_almac, a->almac, 6)) + a->depth = 0; + set_value_by_string("mapagent", "agent", "controller_mac", mac_str, UCI_TYPE_STRING); dbg("|%s:%d| new controller found! Activate ACS configuration"\ @@ -3087,19 +3175,28 @@ int handle_backhaul_sta_caps_query(void *agent, struct cmdu_cstruct *cmdu) return 0; } +int handle_backhaul_sta_caps_report(void *agent, struct cmdu_cstruct *cmdu) +{ + trace("%s: --->\n", __func__); + return 0; +} + + /* Cmdu handlers commented out in the following two tables should be * handled in the controller. * Agent must implement the send cmdu functions corresponding to the * same. */ -#define CMDU_TYPE_1905_START 0x0001 +#define CMDU_TYPE_1905_START 0x0000 #define CMDU_TYPE_1905_END 0x000a static const map_cmdu_handler_t i1905ftable[] = { + [0x00] = handle_topology_discovery, [0x01] = handle_topology_notification, [0x02] = handle_topology_query, [0x03] = handle_topology_response, + [0x04] = handle_vendor_specific, /* hole */ /* [0x07] = handle_ap_autoconfig_search, */ [0x08] = handle_ap_autoconfig_response, @@ -3109,7 +3206,7 @@ static const map_cmdu_handler_t i1905ftable[] = { #define CMDU_TYPE_MAP_START 0x8000 -#define CMDU_TYPE_MAP_END 0x8033 +#define CMDU_TYPE_MAP_END 0x8027 static const map_cmdu_handler_t agent_mapftable[] = { [0x00] = handle_1905_ack, @@ -3150,7 +3247,7 @@ static const map_cmdu_handler_t agent_mapftable[] = { /* [0x25] = handle_assoc_status_notification, */ /* [0x26] = handle_tunneled_message, */ [0x27] = handle_backhaul_sta_caps_query, - /* [0x28] = handle_backhaul_sta_caps_report, */ + [0x28] = handle_backhaul_sta_caps_report, /* hole */ /* [0x33] = handle_failed_connection_msg, */ }; @@ -3297,7 +3394,7 @@ static void send_cmdu_cb(struct ubus_request *req, json_object_put(jobj); } -int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu) +uint16_t agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu) { char *tlv_data = NULL; uint16_t tlv_data_len = 1; @@ -3372,7 +3469,7 @@ int agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu) trace("[%s:%d] not present", __func__, __LINE__); goto out; } - fprintf(stderr, " %s -", __func__); test_cmdu(cmdu); + ret = ubus_invoke(a->ubus_ctx, id, "send", b.head, send_cmdu_cb, (void *)&msgid, @@ -3411,7 +3508,7 @@ int agent_handle_map_event(struct agent *a, uint16_t cmdutype, uint16_t mid, if (f[idx]) { cmdu = map_build_cmdu(cmdutype, mid, rxif, src, tlvs); if (cmdu) { - fprintf(stderr, " %s -", __func__); test_cmdu(cmdu); + test_cmdu(cmdu); ret = f[idx](a, cmdu); map_free_cmdu(cmdu); } else { diff --git a/src/core/agent_map.h b/src/core/agent_map.h index 25507baa75bb336bc89e5d80aae0011fce098063..268547582ad7d247b8d5ac8886af3e9199c15263 100644 --- a/src/core/agent_map.h +++ b/src/core/agent_map.h @@ -15,7 +15,7 @@ extern int agent_handle_map_event(struct agent *a, uint16_t cmdutype, 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); +uint16_t agent_send_cmdu(struct agent *a, struct cmdu_cstruct *cmdu); int send_channel_sel_response(void *agent, struct cmdu_cstruct *cmdu, struct channel_response *rec_cmdu, uint32_t channel_response_nr); int agent_fill_radio_max_preference(void *agent, diff --git a/src/core/agent_tlv_generator.c b/src/core/agent_tlv_generator.c index d87296d502c16d17550e209103f4a5051ea238b3..f150e0fda67362c105a5baafa0b56b5d60d28cbe 100644 --- a/src/core/agent_tlv_generator.c +++ b/src/core/agent_tlv_generator.c @@ -1543,3 +1543,33 @@ int agent_fill_backhaul_bss_config(struct agent *a, return 0; } + +struct tlv_vendor_specific *agent_gen_vendor_specific_tlv(struct agent *a, uint8_t depth) +{ + struct tlv_vendor_specific *p; + + p = calloc(1, sizeof(*p)); + if (!p) + return NULL; + + p->tlv_type = TLV_TYPE_VENDOR_SPECIFIC; + /* IOPSYS vendor oui */ + p->vendor_oui[0] = 0x00; + p->vendor_oui[1] = 0x22; + p->vendor_oui[2] = 0x07; + + p->m_nr = 1 + 1 + 2 + 1; // number of tlvs, type, len, val + p->m = calloc(1, p->m_nr); + if (!p->m) + goto error; + + p->m[0] = 0x01; + p->m[1] = VENDOR_SPECIFIC_TYPE_DEPTH; + p->m[3] = 1; + p->m[4] = depth; + + return p; +error: + free(p); + return NULL; +} diff --git a/src/core/agent_tlv_generator.h b/src/core/agent_tlv_generator.h index 5c4117eb37c737745bb80225fe396b93ab445021..71be941a26bedead31b873d13a29ff9233d31e01 100644 --- a/src/core/agent_tlv_generator.h +++ b/src/core/agent_tlv_generator.h @@ -10,6 +10,8 @@ #ifndef CNTLR_TLV_GEN_H #define CNTLR_TLV_GEN_H +#define VENDOR_SPECIFIC_TYPE_DEPTH 0x0a + int get_radio_index(struct agent *a, uint8_t *mac); int get_bss_index(struct wifi_radio_element *radio, uint8_t *bssid); int get_radio_and_bss_index(struct agent *a, uint8_t *bssid, int *radio_index); @@ -72,6 +74,8 @@ struct tlv_tunnel_msg_type *agent_gen_tunnel_msg_type( struct agent *a, uint8_t protocol); struct tlv_tunneled *agent_gen_tunneled(struct agent *a, int frame_len, uint8_t *frame_body); +struct tlv_vendor_specific *agent_gen_vendor_specific_tlv(struct agent *a, uint8_t depth); + /* Policy config related functions */ int agent_fill_steering_policy(struct agent *a, diff --git a/src/core/config.c b/src/core/config.c index 34be6920c4a03f257a5e871f9cf5b5a8b0de997f..a702c36059949c7e72ad6102241c92695a1e7b77 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -1942,6 +1942,109 @@ static void wifi_radio_status_cb(struct ubus_request *req, int type, *band = BAND_UNKNOWN; } +void config_disable_bstas(struct agent_config *cfg) +{ + struct uci_context *ctx = NULL; + struct uci_package *pkg; + struct uci_section *section; + struct netif_bkcfg *bk; + bool reload = false; + + + list_for_each_entry(bk, &cfg->bklist, list) { + /* only disable onboarded bsta */ +// if (!bk->cfg->onboarded) +// continue; + + /* disable from wireless config */ + pkg = uci_load_pkg(&ctx, UCI_WIRELESS); + if (!pkg) + continue; + + section = config_get_section(ctx, pkg, UCI_WLAN_IFACE, "ifname", bk->name); + if (!section) { + uci_unload(ctx, pkg); + continue; + } + + set_value(ctx, pkg, section, "disabled", "1", UCI_TYPE_STRING); + uci_save(ctx, pkg); + reload = true; + } + + if (reload) { + uci_commit(ctx, &pkg, false); + uci_unload(ctx, pkg); + } + + + list_for_each_entry(bk, &cfg->bklist, list) { + pkg = uci_load_pkg(&ctx, UCI_AGENT); + if (!pkg) + continue; + + section = config_get_section(ctx, pkg, UCI_BK_AGENT, "ifname", bk->name); + if (!section) { + uci_unload(ctx, pkg); + continue; + } + + set_value(ctx, pkg, section, "enabled", "0", UCI_TYPE_STRING); + uci_save(ctx, pkg); + bk->enabled = 0; + } + + if (reload) { + uci_commit(ctx, &pkg, false); + uci_reload_services("wireless"); + } + + uci_free_context(ctx); +} + +int config_disable_bsta(struct netif_bkcfg *bk) +{ + struct uci_context *ctx = NULL; + struct uci_package *pkg; + struct uci_section *section; + int ret = -1; + + /* disable mapagent bk-iface section */ + pkg = uci_load_pkg(&ctx, UCI_AGENT); + if (!pkg) + return -1; + + section = config_get_section(ctx, pkg, UCI_BK_AGENT, "ifname", bk->name); + if (!section) + goto out_pkg; + + set_value(ctx, pkg, section, "enabled", "0", UCI_TYPE_STRING); + uci_save(ctx, pkg); + bk->enabled = 0; + uci_commit(ctx, &pkg, false); + uci_unload(ctx, pkg); + + /* disable wireless config bsta wifi-iface section */ + pkg = uci_load_pkg(&ctx, UCI_WIRELESS); + if (!pkg) + goto out; + + section = config_get_section(ctx, pkg, UCI_WLAN_IFACE, "ifname", bk->name); + if (!section) + goto out_pkg; + + set_value(ctx, pkg, section, "disabled", "1", UCI_TYPE_STRING); + uci_save(ctx, pkg); + uci_commit(ctx, &pkg, false); + ret = 0; + +out_pkg: + uci_unload(ctx, pkg); +out: + uci_free_context(ctx); + return ret; +} + bool config_find_bsta_agent(struct agent_config *cfg, struct uci_context *ctx, char *device) { diff --git a/src/core/config.h b/src/core/config.h index 075058d4396361af0ba8314ef058592088a07c49..fbbaa3c2e385dd07f6dcd5cfaa79557929922831 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -261,4 +261,7 @@ int wifi_reorder_interfaces(struct agent_config *ac); int uci_set_bridge(char *config, char *bridge, char *proto, char *ipaddress); int uci_add_dhcp(char *interface); int uci_add_fw(struct agent_config *cfg, char *interface); +void config_disable_bstas(struct agent_config *cfg); +int config_disable_bsta(struct netif_bkcfg *bk); + #endif