diff --git a/src/cmdu_validate.c b/src/cmdu_validate.c index 2fb70d2bc2faa4788de6b6ce7ce98f14b06dfeac..08c1e4bd0d9f7a0681f5704db339a0c5c8a01a6e 100644 --- a/src/cmdu_validate.c +++ b/src/cmdu_validate.c @@ -817,3 +817,35 @@ bool validate_ap_autoconfig_response(struct cmdu_buff *cmdu, struct tlv *tv[][16 return true; } + +bool validate_topology_notification(struct cmdu_buff *cmdu, struct tlv *tv[][16]) +{ + int ret; + struct tlv_policy d_policy[] = { + [0] = { + .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE, + .present = TLV_PRESENT_ONE, + .minlen = 6, + .maxlen = 6, + }, + [1] = { + .type = MAP_TLV_CLIENT_ASSOCIATION_EVENT, + .present = TLV_PRESENT_OPTIONAL_ONE, + .minlen = 13, + .maxlen = 13, + } + }; + + ret = cmdu_parse_tlvs(cmdu, tv, d_policy, 2); + if (ret) { + fprintf(stderr, "%s: parse_tlv failed\n", __func__); + return false; + } + + if (!tv[0][0]) { + fprintf(stderr, "%s: required tlv missing\n", __func__); + return false; + } + + return true; +} diff --git a/src/cmdu_validate.h b/src/cmdu_validate.h index d173b6da23adc01da9ce8db44fabe4cd31cd22f4..61f8052c51694c39ca7231a9aa0a9c6ed608e2c3 100644 --- a/src/cmdu_validate.h +++ b/src/cmdu_validate.h @@ -9,5 +9,6 @@ bool validate_topology_response(struct cmdu_buff *cmdu, struct tlv *tv_tsp[][16] bool validate_ap_autoconfig_wsc(struct cmdu_buff *cmdu, struct tlv *tv[][16]); bool validate_ap_autoconfig_search(struct cmdu_buff *cmdu, struct tlv *tv[][16]); bool validate_ap_autoconfig_response(struct cmdu_buff *cmdu, struct tlv *tv[][16]); +bool validate_topology_notification(struct cmdu_buff *cmdu, struct tlv *tv[][16]); #endif // CMDU_VALIDATE diff --git a/src/cntlr.c b/src/cntlr.c index 5bf06c369bba339197a64dca391dc406764135e4..51031f644fee06c972536050f39975275c7b8512 100644 --- a/src/cntlr.c +++ b/src/cntlr.c @@ -2503,6 +2503,18 @@ void run_controller(void) cntlr_wait_for_ieee1905(c); + /*Allocating memory for assoc/disassoc events */ + c->sta_events.assoc_events = (struct wifi_assoc_events *) calloc + (MAX_ASSOC_EVENTS, sizeof(struct wifi_assoc_events)); + if (c->sta_events.assoc_events == NULL) + goto out_exit; + c->sta_events.disassoc_events = (struct wifi_disassoc_events *) calloc + (MAX_DISASSOC_EVENTS, sizeof(struct wifi_disassoc_events)); + if (c->sta_events.disassoc_events == NULL) + goto out_exit; + c->sta_events.front_assoc_events = c->sta_events.rear_assoc_events = -1; + c->sta_events.front_disassoc_events = c->sta_events.rear_disassoc_events = -1; + cntlr_config_defaults(c, &c->cfg); { @@ -2561,6 +2573,10 @@ void run_controller(void) uloop_run(); out_exit: + if (c->sta_events.assoc_events) + free(c->sta_events.assoc_events); + if (c->sta_events.disassoc_events) + free(c->sta_events.disassoc_events); map_unsubscribe(ctx, c->subscriber); cntlr_clean_nodelist(c); ubus_unregister_event_handler(ctx, &c->evh); diff --git a/src/cntlr.h b/src/cntlr.h index bd5a73acad4092d6f91e9d5b9b474ad0e1080782..17825ed863013d90b4cf966215dcc5829032d8a4 100644 --- a/src/cntlr.h +++ b/src/cntlr.h @@ -20,6 +20,11 @@ #include "wifi_dataelements.h" +#define MAX_ASSOC_EVENTS 32 +#define MAX_DISASSOC_EVENTS 32 +#define CNTRL_ASSOC_EVENT 1 +#define CNTRL_DISASSOC_EVENT 2 + extern const char *ubus_socket; typedef uint32_t object_t; @@ -382,6 +387,7 @@ struct controller { struct steer_control *sctrl; /* active steer-control module */ struct wifi_data_element dlem; /* wifi data elements */ + struct wifi_sta_events sta_events; /* wifi_sta_events */ }; struct sta_channel_report { diff --git a/src/cntlr_map.c b/src/cntlr_map.c index b2d620772385d2ea6e373b3ba5e5b03ddcb96acb..871ad800d9bd0f195888a6e9d8fe0d68136962fa 100644 --- a/src/cntlr_map.c +++ b/src/cntlr_map.c @@ -60,10 +60,120 @@ struct map_cmdu_calltable_t { map_cmdu_handler_t debug; }; +/* Check if the event queue is full */ +int is_full_event_queue(struct controller *c, int event_type) +{ + if (event_type == CNTRL_ASSOC_EVENT) { + if ((c->sta_events.front_assoc_events == c->sta_events.rear_assoc_events + 1) + || (c->sta_events.front_assoc_events == 0 && + c->sta_events.rear_assoc_events == MAX_ASSOC_EVENTS - 1)) + return 1; + } + else { + if ((c->sta_events.front_disassoc_events == c->sta_events.rear_disassoc_events + 1) + || (c->sta_events.front_disassoc_events == 0 && + c->sta_events.rear_disassoc_events == MAX_DISASSOC_EVENTS - 1)) + return 1; + } + return 0; +} + +/* Enqueue of assoc events*/ +void cntrl_enqueue_assoc_events(struct controller *c, struct wifi_assoc_events *event) +{ + dbg("Inside %s\n", __func__); + struct wifi_assoc_events *elem; + + if (is_full_event_queue(c, CNTRL_ASSOC_EVENT)) { + dbg("assoc event queue full del front node\n"); + c->sta_events.front_assoc_events = (c->sta_events.front_assoc_events + 1) + % MAX_ASSOC_EVENTS; + c->sta_events.num_assoc_events--; + } + + + if (c->sta_events.front_assoc_events == -1) + c->sta_events.front_assoc_events = 0; + + c->sta_events.rear_assoc_events = (c->sta_events.rear_assoc_events + 1) + % MAX_ASSOC_EVENTS; + elem = &(c->sta_events.assoc_events[c->sta_events.rear_assoc_events]); + memset(elem, 0, sizeof(struct wifi_assoc_events)); + memcpy(elem->macaddr, event->macaddr, 6); + memcpy(elem->bssid, event->bssid, 6); + get_timestamp(NULL, elem->tsp); + c->sta_events.num_assoc_events++; +} + +/* Enqueue of disassoc events*/ +void cntrl_enqueue_disassoc_events(struct controller *c, struct wifi_disassoc_events *event) +{ + dbg("Inside %s\n", __func__); + struct wifi_disassoc_events *elem; + + if (is_full_event_queue(c, CNTRL_DISASSOC_EVENT)) { + dbg("disassoc event queue full del front node\n"); + c->sta_events.front_disassoc_events = (c->sta_events.front_disassoc_events + 1) + % MAX_DISASSOC_EVENTS; + c->sta_events.num_disassoc_events--; + } + + if (c->sta_events.front_disassoc_events == -1) + c->sta_events.front_disassoc_events = 0; + + c->sta_events.rear_disassoc_events = (c->sta_events.rear_disassoc_events + 1) + % MAX_DISASSOC_EVENTS; + elem = &(c->sta_events.disassoc_events[c->sta_events.rear_disassoc_events]); + memset(elem, 0, sizeof(struct wifi_disassoc_events)); + memcpy(elem->sta_data.macaddr, event->sta_data.macaddr, 6); + memcpy(elem->bssid, event->bssid, 6); + get_timestamp(NULL, elem->tsp); + c->sta_events.num_disassoc_events++; +} + + + int handle_topology_notification(void *cntlr, struct cmdu_buff *cmdu) { - trace("%s: --->\n", __func__); - return 0; + cntlr = (struct controller *)cntlr; + struct wifi_assoc_events assoc_ev; + struct wifi_disassoc_events disassoc_ev; + struct tlv *tv[2][16]; + struct cmdu_buff *ret = NULL ; + + if (!validate_topology_notification(cmdu, tv)) { + err("%s: cmdu validation "\ + "[TOPOLOGY_NOTIFICATION] failed\n", __func__); + return -1; + } + + if (tv[1][0]) { + struct tlv_client_assoc_event *p = + (struct tlv_client_assoc_event *)tv[1][0]->data; + + if (p->event & CLIENT_EVENT_MASK) { + /* client association */ + memcpy(assoc_ev.macaddr, p->macaddr, 6); + memcpy(assoc_ev.bssid, p->bssid, 6); + cntrl_enqueue_assoc_events(cntlr, &assoc_ev); + + /* Send client capability query */ + ret = cntlr_gen_client_caps_query((struct controller *)cntlr, cmdu->origin, + p->macaddr, p->bssid); + if (ret) { + err("Error in sending client capability query\n"); + return -1; + } + + } else { + /* client disassociation */ + memcpy(disassoc_ev.bssid, p->bssid, 6); + memcpy(disassoc_ev.sta_data.macaddr, p->macaddr, 6); + cntrl_enqueue_disassoc_events(cntlr, &disassoc_ev); + } + } + + return 0; } static void _cntlr_update_steer_params(struct controller *c, struct opclass *op) diff --git a/src/utils/utils.c b/src/utils/utils.c index b4cd5836202528e5a32b78bad2db78346086c980..3554eb6b8153ec6a50947079f363abc0ddcb500d 100644 --- a/src/utils/utils.c +++ b/src/utils/utils.c @@ -539,3 +539,41 @@ int writeto_configfile(const char *filename, void *in, size_t len) close(fp); return 0; } + +char *get_timestamp(time_t *t, char *tbuf) +{ + char tmpbuf[64] = {0}; + struct tm res; + char sign; + long int toff, toff_hour, toff_min; + const time_t now = time(t); + + if (!tbuf) + return NULL; + + /* E.g. "2019-02-11T06:42:31.23039-08:00" */ + + localtime_r(&now, &res); + tzset(); + toff = timezone; + sign = toff > 0 ? '-' : '+'; + toff *= -1L; + + toff_hour = toff / 3600; + toff_min = (toff % 3600) / 60; + + snprintf(tmpbuf, 63, "%04d-%02d-%02dT%02d:%02d:%02d%c%02ld:%02ld", + res.tm_year + 1900, + res.tm_mon + 1, + res.tm_mday, + res.tm_hour, + res.tm_min, + res.tm_sec, + sign, + toff_hour, + toff_min); + snprintf(tbuf, 64, "%s", tmpbuf); + + return tbuf; +} + diff --git a/src/utils/utils.h b/src/utils/utils.h index 9edf07b62a52c00b6d4494430fe413237a1543e7..3f18ef81c91ca26405eaf3a95e5de857d5f50669 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -170,5 +170,6 @@ void do_daemonize(const char *pidfile); int writeto_configfile(const char *filename, void *in, size_t len); int readfrom_configfile(const char *filename, uint8_t **out, size_t *olen); +char *get_timestamp(time_t *t, char *tbuf); #endif /* UTILS_H */ diff --git a/src/wifi_dataelements.h b/src/wifi_dataelements.h index 88551cdef842fa8db5db7616443990d4843a1a12..de836a83419d3a88b582c100858c6dc935adf0a7 100644 --- a/src/wifi_dataelements.h +++ b/src/wifi_dataelements.h @@ -617,12 +617,14 @@ struct wifi_disassoc_events { }; struct wifi_sta_events { - uint32_t old_assoc_events; - uint32_t old_disassoc_events; + uint32_t front_assoc_events; + uint32_t rear_assoc_events; + uint32_t front_disassoc_events; + uint32_t rear_disassoc_events; uint32_t num_assoc_events; uint32_t num_disassoc_events; - struct list_head assoc_eventlist; /* list of wifi_assoc_events */ - struct list_head disassoc_eventlist; /* list of wifi_disassoc_events */ + struct wifi_assoc_events *assoc_events; /* wifi_assoc_events */ + struct wifi_disassoc_events *disassoc_events; /* wifi_disassoc_events */ }; struct wifi_channel_data {