--- a/hostapd/main.c +++ b/hostapd/main.c @@ -41,7 +41,7 @@ struct hapd_global { static struct hapd_global global; static int daemonize = 0; static char *pid_file = NULL; - +uint32_t cached_events_nr = 0; #ifndef CONFIG_NO_HOSTAPD_LOGGER static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module, --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -97,6 +97,10 @@ struct hostapd_probereq_cb { }; #define HOSTAPD_RATE_BASIC 0x00000001 +/* max number of cached events */ +#define HOSTAPD_MAX_CACHED_EVENTS 500 +/* event counter */ +uint32_t cached_events_nr; struct hostapd_rate_data { int rate; /* rate in 100 kbps */ --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -4908,6 +4908,7 @@ int ieee802_11_mgmt(struct hostapd_data int ret = 0; unsigned int freq; int ssi_signal = fi ? fi->ssi_signal : 0; + int ubus_resp; if (len < 24) return 0; @@ -4977,25 +4978,52 @@ int ieee802_11_mgmt(struct hostapd_data if (hapd->iconf->track_sta_max_num) sta_track_add(hapd->iface, mgmt->sa, ssi_signal); + /* ubus request */ + struct hostapd_ubus_request req = { + .type = HOSTAPD_UBUS_TYPE_MAX, + .mgmt_frame = mgmt, + .ssi_signal = ssi_signal + }; + switch (stype) { case WLAN_FC_STYPE_AUTH: wpa_printf(MSG_DEBUG, "mgmt::auth"); handle_auth(hapd, mgmt, len, ssi_signal, 0); + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "mgmt: [%d] [%s]", + stype, + "AUTH"); + req.type = HOSTAPD_UBUS_AUTH_REQ; ret = 1; break; case WLAN_FC_STYPE_ASSOC_REQ: wpa_printf(MSG_DEBUG, "mgmt::assoc_req"); handle_assoc(hapd, mgmt, len, 0, ssi_signal); + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "mgmt: [%d] [%s]", + stype, + "ASSOC"); + req.type = HOSTAPD_UBUS_ASSOC_REQ; ret = 1; break; case WLAN_FC_STYPE_REASSOC_REQ: wpa_printf(MSG_DEBUG, "mgmt::reassoc_req"); handle_assoc(hapd, mgmt, len, 1, ssi_signal); + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "mgmt: [%d] [%s]", + stype, + "RE-ASSOC"); + req.type = HOSTAPD_UBUS_REASSOC_REQ; ret = 1; break; case WLAN_FC_STYPE_DISASSOC: wpa_printf(MSG_DEBUG, "mgmt::disassoc"); handle_disassoc(hapd, mgmt, len); + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "mgmt: [%d] [%s]", + stype, + "DISASSOC"); + req.type = HOSTAPD_UBUS_DISASSOC_REQ; ret = 1; break; case WLAN_FC_STYPE_DEAUTH: @@ -5014,6 +5042,15 @@ int ieee802_11_mgmt(struct hostapd_data break; } + /* ubus send */ + if (req.type != HOSTAPD_UBUS_TYPE_MAX) { + ubus_resp = hostapd_ubus_handle_rt_event(hapd, &req); + if (ubus_resp) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, + "hostapd_ubus_handle_rt_event: ERROR"); + } + } return ret; } --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -423,8 +423,14 @@ void ap_handle_timer(void *eloop_ctx, vo hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " "local deauth request"); - ap_free_sta(hapd, sta); hostapd_ubus_notify(hapd, "local-deauth", sta->addr); + struct hostapd_ubus_request req = { + .type = HOSTAPD_UBUS_DISASSOC_REQ, + .sta = sta, + .reason = sta->deauth_reason + }; + hostapd_ubus_handle_rt_event(hapd, &req); + ap_free_sta(hapd, sta); return; } @@ -530,6 +536,14 @@ skip_poll: WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY : WLAN_REASON_PREV_AUTH_NOT_VALID; + /* sessions */ + struct hostapd_ubus_request req = { + .type = HOSTAPD_UBUS_DISASSOC_REQ, + .sta = sta, + .reason = reason + }; + hostapd_ubus_handle_rt_event(hapd, &req); + hostapd_drv_sta_disassoc(hapd, sta->addr, reason); } } @@ -566,6 +580,15 @@ skip_poll: __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY); eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, hapd, sta); + + /* sessions */ + struct hostapd_ubus_request req = { + .type = HOSTAPD_UBUS_DISASSOC_REQ, + .sta = sta, + .reason = reason + }; + hostapd_ubus_handle_rt_event(hapd, &req); + mlme_disassociate_indication(hapd, sta, reason); break; case STA_DEAUTH: --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -77,6 +77,9 @@ struct sta_info { u8 supported_rates[WLAN_SUPP_RATES_MAX]; int supported_rates_len; u8 qosinfo; /* Valid when WLAN_STA_WMM is set */ + u64 cl_session_id; /* client fnv1a 64bit session id */ + u8 fdata; /* client first data flag */ + u8 first_ip; /* client first ip flag */ #ifdef CONFIG_MESH enum mesh_plink_state plink_state; --- a/src/ap/ubus.c +++ b/src/ap/ubus.c @@ -24,7 +24,10 @@ static struct ubus_context *ctx; static struct blob_buf b; +static struct blob_buf b_ev; static int ctx_ref; +static char** bss_lst = NULL; +static size_t bss_nr = 0; static inline struct hapd_interfaces *get_hapd_interfaces_from_object(struct ubus_object *obj) { @@ -63,6 +66,21 @@ static void hostapd_ubus_connection_lost eloop_register_timeout(1, 0, ubus_reconnect_timeout, ctx, NULL); } +static int avl_compare_sess_id(const void *k1, const void *k2, void *ptr) +{ + const uint32_t *id1 = k1, *id2 = k2; + + if (*id1 < *id2) + return -1; + else + return *id1 > *id2; +} + +uint64_t get_time_in_ms(struct timespec *ts) +{ + return (uint64_t) ts->tv_sec * 1000 + ts->tv_nsec / 1000000; +} + static bool hostapd_ubus_init(void) { if (ctx) @@ -525,6 +543,177 @@ static const struct blobmsg_policy csa_p }; #ifdef NEED_AP_MLME +enum { CSESS_REQ_SESS_ID, + __CSESS_REQ_MAX, +}; + +static const struct blobmsg_policy client_session_del_policy[__CSESS_REQ_MAX] = { + [CSESS_REQ_SESS_ID] = { .name = "session_id", .type = BLOBMSG_TYPE_INT64 }, +}; + +static int hostapd_clear_session(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct blob_attr *tb[__CSESS_REQ_MAX]; + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + struct hostapd_event_avl_rec *rec = NULL; + struct hostapd_event_avl_rec *rec_next = NULL; + uint64_t session_id = 0; + + blobmsg_parse(client_session_del_policy, __CSESS_REQ_MAX, tb, + blob_data(msg), blob_len(msg)); + + if (!tb[CSESS_REQ_SESS_ID]) + return UBUS_STATUS_INVALID_ARGUMENT; + + session_id = blobmsg_get_u64(tb[CSESS_REQ_SESS_ID]); + /* remove from AVL and ubus session object) */ + avl_for_each_element_safe(&hapd->ubus.rt_events, rec, avl, rec_next) + { + if (session_id == rec->session_id) { + /* dec counter and delete */ + cached_events_nr -= rec->rec_nr; + avl_delete(&hapd->ubus.rt_events, &rec->avl); + os_free(rec->records); + os_free(rec); + } + } + return 0; +} + +static int hostapd_clear_sessions(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + struct hostapd_event_avl_rec *rec = NULL; + struct hostapd_event_avl_rec *rec_n = NULL; + + avl_remove_all_elements(&hapd->ubus.rt_events, rec, avl, rec_n) + { + /* free events array */ + os_free(rec->records); + os_free(rec); + } + /* reset counter */ + cached_events_nr = 0; + return 0; +} + +static int hostapd_sessions(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + struct hostapd_data *hapd = container_of(obj, struct hostapd_data, ubus.obj); + void *a = NULL; + void *t = NULL; + void *t_msg = NULL; + struct hostapd_event_avl_rec *rec = NULL; + struct client_session_record *c_rec = NULL; + + blob_buf_init(&b_ev, 0); + a = blobmsg_open_table(&b_ev, "sessions"); + avl_for_each_element(&hapd->ubus.rt_events, rec, avl) + { + /* open session */ + t = blobmsg_open_table(&b_ev, "ClientSession"); + blobmsg_add_u64(&b_ev, "session_id", rec->session_id); + /* messages for current session */ + for (size_t i = 0; i < rec->rec_nr; i++) { + c_rec = &rec->records[i]; + /* check message type */ + switch (c_rec->type) { + /* ClientAuthEvent */ + case CST_AUTH: { + struct client_auth_event *p = &c_rec->u.auth; + t_msg = blobmsg_open_table(&b_ev, "ClientAuthEvent"); + blobmsg_add_u64(&b_ev, "session_id", rec->session_id); + blobmsg_add_u64(&b_ev, "timestamp", c_rec->timestamp); + blobmsg_add_string(&b_ev, "sta_mac", p->sta_mac); + blobmsg_add_u32(&b_ev, "band", p->band); + blobmsg_add_u32(&b_ev, "auth_status", p->auth_status); + blobmsg_add_string(&b_ev, "ssid", p->ssid); + blobmsg_close_table(&b_ev, t_msg); + break; + } + + /* ClientAssocEvent */ + case CST_ASSOC: { + struct client_assoc_event *p = &c_rec->u.assoc; + t_msg = blobmsg_open_table(&b_ev, "ClientAssocEvent"); + blobmsg_add_u64(&b_ev, "session_id", rec->session_id); + blobmsg_add_u64(&b_ev, "timestamp", c_rec->timestamp); + blobmsg_add_string(&b_ev, "sta_mac", p->sta_mac); + blobmsg_add_u32(&b_ev, "band", p->band); + blobmsg_add_u32(&b_ev, "assoc_type", 0); + blobmsg_add_u32(&b_ev, "rssi", p->rssi); + blobmsg_add_u32(&b_ev, "internal_sc", 0); + blobmsg_add_u8(&b_ev, "using11k", p->using11k); + blobmsg_add_u8(&b_ev, "using11r", p->using11r); + blobmsg_add_u8(&b_ev, "using11v", p->using11v); + blobmsg_add_string(&b_ev, "ssid", p->ssid); + blobmsg_close_table(&b_ev, t_msg); + break; + } + + /* ClientDisconnectEvent */ + case CST_DISASSOC: { + struct client_disassoc_event *p = &c_rec->u.disassoc; + t_msg = blobmsg_open_table(&b_ev, "ClientDisconnectEvent"); + blobmsg_add_u64(&b_ev, "session_id", rec->session_id); + blobmsg_add_u64(&b_ev, "timestamp", c_rec->timestamp); + blobmsg_add_string(&b_ev, "sta_mac", p->sta_mac); + blobmsg_add_u32(&b_ev, "band", p->band); + blobmsg_add_u32(&b_ev, "rssi", p->rssi); + blobmsg_add_u32(&b_ev, "internal_rc", p->internal_rc); + blobmsg_add_string(&b_ev, "ssid", p->ssid); + blobmsg_close_table(&b_ev, t_msg); + break; + } + + /* ClientFirstDataEvent */ + case CST_FDATA: { + struct client_fdata_event *p = &c_rec->u.fdata; + t_msg = blobmsg_open_table(&b_ev, "ClientFirstDataEvent"); + blobmsg_add_u64(&b_ev, "session_id", rec->session_id); + blobmsg_add_u64(&b_ev, "timestamp", c_rec->timestamp); + blobmsg_add_string(&b_ev, "sta_mac", p->sta_mac); + blobmsg_add_u64(&b_ev, "fdata_tx_up_ts_in_us", p->tx_ts.tv_sec * (uint64_t)1000000); + blobmsg_add_u64(&b_ev, "fdata_rx_up_ts_in_us", p->rx_ts.tv_sec * (uint64_t)1000000); + blobmsg_close_table(&b_ev, t_msg); + break; + } + + /* ClientIpEvent */ + case CST_IP: { + struct client_ip_event *p = &c_rec->u.ip; + t_msg = blobmsg_open_table(&b_ev, "ClientIpEvent"); + blobmsg_add_u64(&b_ev, "session_id", rec->session_id); + blobmsg_add_u64(&b_ev, "timestamp", c_rec->timestamp); + blobmsg_add_string(&b_ev, "sta_mac", p->sta_mac); + blobmsg_add_string(&b_ev, "ip_address", p->ip_addr); + blobmsg_close_table(&b_ev, t_msg); + break; + } + + default: + break; + } + } + blobmsg_close_table(&b_ev, t); + } + blobmsg_close_table(&b_ev, a); + ubus_send_reply(ctx, req, b_ev.head); + return 0; +} + static int hostapd_switch_chan(struct ubus_context *ctx, struct ubus_object *obj, struct ubus_request_data *req, const char *method, @@ -1148,6 +1337,9 @@ static const struct ubus_method bss_meth UBUS_METHOD_NOARG("get_features", hostapd_bss_get_features), #ifdef NEED_AP_MLME UBUS_METHOD("switch_chan", hostapd_switch_chan, csa_policy), + UBUS_METHOD_NOARG("get_sessions", hostapd_sessions), + UBUS_METHOD_NOARG("clear_sessions", hostapd_clear_sessions), + UBUS_METHOD("clear_session", hostapd_clear_session, client_session_del_policy), #endif UBUS_METHOD("set_vendor_elements", hostapd_vendor_elements, ve_policy), UBUS_METHOD("notify_response", hostapd_notify_response, notify_policy), @@ -1187,6 +1379,7 @@ void hostapd_ubus_add_bss(struct hostapd if (asprintf(&name, "hostapd.%s", hapd->conf->iface) < 0) return; + avl_init(&hapd->ubus.rt_events, avl_compare_sess_id, false, NULL); avl_init(&hapd->ubus.banned, avl_compare_macaddr, false, NULL); obj->name = name; obj->type = &bss_object_type; @@ -1194,6 +1387,9 @@ void hostapd_ubus_add_bss(struct hostapd obj->n_methods = bss_object_type.n_methods; ret = ubus_add_object(ctx, obj); hostapd_ubus_ref_inc(); + bss_nr++; + bss_lst = os_realloc(bss_lst, sizeof(char *) * bss_nr); + bss_lst[bss_nr - 1] = strdup(name); if (hapd->conf->signal_stay_min > -128) eloop_register_timeout(3, 0, hostapd_bss_signal_check, NULL, hapd); /* Start up the poll timer. */ } @@ -1212,11 +1408,42 @@ void hostapd_ubus_free_bss(struct hostap } free(name); + for (size_t i = 0; i < bss_nr; i++) + os_free(bss_lst[i]); + free(bss_lst); + bss_lst = NULL; +} + +static int hostapd_get_bss_list(struct ubus_context *ctx, + struct ubus_object *obj, + struct ubus_request_data *req, + const char *method, + struct blob_attr *msg) +{ + if (!bss_lst) + return 0; + + void *a = NULL; + void *b = NULL; + + /* create reply */ + blob_buf_init(&b_ev, 0); + a = blobmsg_open_array(&b_ev, "bss_list"); + /* check bss list from hapd */ + for (size_t i = 0; i < bss_nr; i++) { + b = blobmsg_open_table(&b_ev, NULL); + blobmsg_add_string(&b_ev, "name", bss_lst[i]); + blobmsg_close_table(&b_ev, b); + } + blobmsg_close_array(&b_ev, a); + ubus_send_reply(ctx, req, b_ev.head); + return 0; } static const struct ubus_method daemon_methods[] = { UBUS_METHOD("config_add", hostapd_config_add, config_add_policy), UBUS_METHOD("config_remove", hostapd_config_remove, config_remove_policy), + UBUS_METHOD_NOARG("get_bss_list", hostapd_get_bss_list), }; static struct ubus_object_type daemon_object_type = @@ -1260,6 +1487,18 @@ struct ubus_event_req { int resp; }; +static uint64_t hash_fnv1a_64bit(const void *key, int len) +{ + if (key == NULL) + return 0; + unsigned char *p = (unsigned char *)key; + uint64_t h = 14695981039346656037UL; + int i; + for (i = 0; i < len; i++) + h = (h ^ p[i]) * 1099511628211UL; + return h; +} + static void ubus_event_cb(struct ubus_notify_request *req, int idx, int ret) { @@ -1268,6 +1507,224 @@ ubus_event_cb(struct ubus_notify_request ureq->resp = ret; } +int hostapd_ubus_handle_rt_event(struct hostapd_data *hapd, + struct hostapd_ubus_request *req) +{ + /* check event counter */ + if (cached_events_nr > HOSTAPD_MAX_CACHED_EVENTS) { + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_WARNING, + "hostapd_ubus_handle_rt_event: HOSTAPD_MAX_CACHED_EVENTS [%d] exceeded", + HOSTAPD_MAX_CACHED_EVENTS); + return WLAN_STATUS_SUCCESS; + } + struct hostapd_event_avl_rec *rec = NULL; + struct timespec ts; + uint64_t timestamp = 0; + clock_gettime(CLOCK_REALTIME, &ts); + timestamp = get_time_in_ms(&ts); + uint64_t session_id = 0; + uint8_t new_rec = 0; + const struct ieee80211_mgmt *mgmt = req->mgmt_frame; + struct sta_info *sta = req->sta ? (void *)req->sta : ap_get_sta(hapd, mgmt->sa); + /* null pointer check */ + if (!sta) return WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + + struct hostapd_bss_config *bss_conf = hapd->conf; + session_id = sta->cl_session_id; + + /* find by session id */ + rec = avl_find_element(&hapd->ubus.rt_events, &session_id, rec, avl); + + /* prepare rec if not found */ + if (!rec) { + new_rec = 1; + rec = os_zalloc(sizeof(struct hostapd_event_avl_rec)); + session_id = hash_fnv1a_64bit(&ts, sizeof(struct timespec)); + } + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event: REQ TYPE [%d]", + req->type); + + switch (req->type) { + case HOSTAPD_UBUS_AUTH_REQ: { + /* session id */ + rec->session_id = session_id; + rec->rec_nr++; + rec->records = os_realloc(rec->records, + sizeof(struct client_session_record) * rec->rec_nr); + struct client_session_record *rp = &rec->records[rec->rec_nr - 1]; + rp->type = CST_AUTH; + rp->u.auth.session_id = rec->session_id; + + /* timestamp */ + rp->timestamp = timestamp; + /* frequency */ + rp->u.auth.band = hapd->iface->freq; + /* STA MAC */ + sprintf(rp->u.auth.sta_mac, MACSTR, MAC2STR(sta->addr)); + /* ssid */ + rp->u.auth.ssid[0] = 0; + printf_encode(rp->u.auth.ssid, sizeof(rp->u.auth.ssid), + bss_conf->ssid.ssid, bss_conf->ssid.ssid_len); + /* auth status */ + rp->u.auth.auth_status = le_to_host16(mgmt->u.auth.status_code); + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event:HOSTAPD_UBUS_AUTH_REQ"); + /* inc counter */ + cached_events_nr++; + break; + } + case HOSTAPD_UBUS_ASSOC_REQ: { + /* session id */ + rec->session_id = session_id; + rec->rec_nr++; + rec->records = os_realloc(rec->records, + sizeof(struct client_session_record) * rec->rec_nr); + struct client_session_record *rp = &rec->records[rec->rec_nr - 1]; + rp->type = CST_ASSOC; + rp->u.assoc.session_id = rec->session_id; + /* timestamp */ + rp->timestamp = timestamp; + /* frequency */ + rp->u.assoc.band = hapd->iface->freq; + /* STA MAC */ + sprintf(rp->u.assoc.sta_mac, MACSTR, MAC2STR(sta->addr)); + /* ssid */ + rp->u.assoc.ssid[0] = 0; + printf_encode(rp->u.assoc.ssid, sizeof(rp->u.assoc.ssid), + bss_conf->ssid.ssid, bss_conf->ssid.ssid_len); + /* rssi */ + rp->u.assoc.rssi = req->ssi_signal; + /* using 11r */ + rp->u.assoc.using11r = (sta->auth_alg & WPA_AUTH_ALG_FT); + /* using 11k */ + if (sta->rrm_enabled_capa[0] || sta->rrm_enabled_capa[1] || + sta->rrm_enabled_capa[2] || sta->rrm_enabled_capa[3] || + sta->rrm_enabled_capa[4]) + rp->u.assoc.using11k = 1; + else + rp->u.assoc.using11k = 0; + /* using 11v */ + if (bss_conf->time_advertisement || bss_conf->wnm_sleep_mode || + bss_conf->bss_transition) + rp->u.assoc.using11v = 1; + else + rp->u.assoc.using11v = 0; + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event:HOSTAPD_UBUS_ASSOC_REQ"); + /* inc counter */ + cached_events_nr++; + break; + } + case HOSTAPD_UBUS_DISASSOC_REQ: { + /* session id */ + rec->session_id = session_id; + rec->rec_nr++; + rec->records = os_realloc(rec->records, + sizeof(struct client_session_record) * rec->rec_nr); + struct client_session_record *rp = &rec->records[rec->rec_nr - 1]; + rp->type = CST_DISASSOC; + rp->u.disassoc.session_id = rec->session_id; + /* timestamp */ + rp->timestamp = timestamp; + /* frequency */ + rp->u.disassoc.band = hapd->iface->freq; + /* STA MAC */ + sprintf(rp->u.disassoc.sta_mac, MACSTR, MAC2STR(sta->addr)); + /* ssid */ + rp->u.disassoc.ssid[0] = 0; + printf_encode(rp->u.disassoc.ssid, sizeof(rp->u.disassoc.ssid), + bss_conf->ssid.ssid, bss_conf->ssid.ssid_len); + /* rssi */ + rp->u.disassoc.rssi = req->ssi_signal; + /* internal_rc */ + rp->u.disassoc.internal_rc = req->reason; + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event:HOSTAPD_UBUS_DISASSOC_REQ"); + /* inc counter */ + cached_events_nr++; + break; + } + case HOSTAPD_UBUS_FDATA_REQ: { + /* session id */ + rec->session_id = session_id; + rec->rec_nr++; + rec->records = os_realloc(rec->records, + sizeof(struct client_session_record) * rec->rec_nr); + struct client_session_record *rp = &rec->records[rec->rec_nr - 1]; + rp->type = CST_FDATA; + rp->u.fdata.session_id = rec->session_id; + /* timestamp */ + rp->timestamp = timestamp; + /* STA MAC */ + sprintf(rp->u.fdata.sta_mac, MACSTR, MAC2STR(sta->addr)); + /* rx ts */ + rp->u.fdata.rx_ts = ts; + /* tx ts */ + rp->u.fdata.tx_ts = ts; + /* single event only */ + sta->fdata = 1; + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event:HOSTAPD_UBUS_FDATA_REQ"); + /* inc counter */ + cached_events_nr++; + break; + } + case HOSTAPD_UBUS_IP_REQ: { + if(sta->first_ip) break; + /* session id */ + rec->session_id = session_id; + rec->rec_nr++; + rec->records = os_realloc(rec->records, + sizeof(struct client_session_record) * rec->rec_nr); + struct client_session_record *rp = &rec->records[rec->rec_nr - 1]; + rp->type = CST_IP; + rp->u.ip.session_id = rec->session_id; + /* timestamp */ + rp->timestamp = timestamp; + /* STA MAC */ + sprintf(rp->u.ip.sta_mac, MACSTR, MAC2STR(sta->addr)); + /* ip address */ + snprintf(rp->u.ip.ip_addr, 20, "%u.%u.%u.%u", + (req->ipaddr >> 24) & 0xFF, + (req->ipaddr >> 16) & 0xFF, + (req->ipaddr >> 8) & 0xFF, + req->ipaddr & 0xFF); + /* single event only */ + sta->first_ip = 1; + /* inc counter */ + cached_events_nr++; + break; + } + default: + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event:UNKNOWN"); + new_rec = 0; + break; + } + if (new_rec) { + /* insert new client session */ + rec->avl.key = &rec->session_id; + sta->cl_session_id = session_id; + if (avl_insert(&hapd->ubus.rt_events, &rec->avl)) + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + return WLAN_STATUS_SUCCESS; +} + int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req) { struct ubus_banned_client *ban; --- a/src/ap/ubus.h +++ b/src/ap/ubus.h @@ -12,6 +12,11 @@ enum hostapd_ubus_event_type { HOSTAPD_UBUS_PROBE_REQ, HOSTAPD_UBUS_AUTH_REQ, HOSTAPD_UBUS_ASSOC_REQ, + HOSTAPD_UBUS_REASSOC_REQ, + HOSTAPD_UBUS_DISASSOC_REQ, + HOSTAPD_UBUS_DEAUTH_REQ, + HOSTAPD_UBUS_FDATA_REQ, + HOSTAPD_UBUS_IP_REQ, HOSTAPD_UBUS_TYPE_MAX }; @@ -19,8 +24,11 @@ struct hostapd_ubus_request { enum hostapd_ubus_event_type type; const struct ieee80211_mgmt *mgmt_frame; const struct ieee802_11_elems *elems; + const struct sta_info *sta; int ssi_signal; /* dBm */ + int reason; const u8 *addr; + be32 ipaddr; }; struct hostapd_iface; @@ -37,6 +45,80 @@ struct hostapd_ubus_bss { struct ubus_object obj; struct avl_tree banned; int notify_response; + struct avl_tree rt_events; +}; + +enum client_sess_type { + CST_ASSOC, + CST_AUTH, + CST_DISASSOC, + CST_FDATA, + CST_IP +}; + +struct client_assoc_event { + unsigned char sta_mac[20]; + uint64_t session_id; + char ssid[SSID_MAX_LEN]; + int band; + int assoc_type; + int status; + int rssi; + int internal_sc; + uint8_t using11k; + uint8_t using11r; + uint8_t using11v; +}; + +struct client_disassoc_event { + unsigned char sta_mac[20]; + uint64_t session_id; + char ssid[SSID_MAX_LEN]; + int band; + int assoc_type; + int status; + int rssi; + int internal_rc; +}; + +struct client_auth_event { + unsigned char sta_mac[20]; + uint64_t session_id; + char ssid[SSID_MAX_LEN]; + int band; + uint32_t auth_status; +}; + +struct client_fdata_event { + unsigned char sta_mac[20]; + uint64_t session_id; + struct timespec rx_ts; + struct timespec tx_ts; +}; + +struct client_ip_event { + unsigned char sta_mac[20]; + uint64_t session_id; + unsigned char ip_addr[16]; +}; + +struct client_session_record { + int type; + uint64_t timestamp; + union { + struct client_assoc_event assoc; + struct client_disassoc_event disassoc; + struct client_auth_event auth; + struct client_fdata_event fdata; + struct client_ip_event ip; + } u; +}; + +struct hostapd_event_avl_rec { + uint64_t session_id; + struct client_session_record *records; + size_t rec_nr; + struct avl_node avl; }; void hostapd_ubus_add_iface(struct hostapd_iface *iface); @@ -45,6 +127,7 @@ void hostapd_ubus_add_bss(struct hostapd void hostapd_ubus_free_bss(struct hostapd_data *hapd); int hostapd_ubus_handle_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req); +int hostapd_ubus_handle_rt_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req); void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac); void hostapd_ubus_notify_beacon_report(struct hostapd_data *hapd, const u8 *addr, u8 token, u8 rep_mode, @@ -78,6 +161,11 @@ static inline int hostapd_ubus_handle_ev { return 0; } + +static inline int hostapd_ubus_handle_rt_event(struct hostapd_data *hapd, struct hostapd_ubus_request *req) +{ + return 0; +} static inline void hostapd_ubus_notify(struct hostapd_data *hapd, const char *type, const u8 *mac) { --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1406,19 +1406,22 @@ static int hostapd_setup_bss(struct host "Generic snooping infrastructure initialization failed"); return -1; } - - if (dhcp_snoop_init(hapd)) { - wpa_printf(MSG_ERROR, - "DHCP snooping initialization failed"); - return -1; - } - if (ndisc_snoop_init(hapd)) { wpa_printf(MSG_ERROR, "Neighbor Discovery snooping initialization failed"); return -1; } } + if (dhcp_snoop_init(hapd)) { + wpa_printf(MSG_ERROR, + "DHCP snooping initialization failed"); + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "dfranusic:DHCP snooping initialization failed"); + + return -1; + } if (!hostapd_drv_none(hapd) && vlan_init(hapd)) { wpa_printf(MSG_ERROR, "VLAN initialization failed."); --- a/src/ap/dhcp_snoop.c +++ b/src/ap/dhcp_snoop.c @@ -40,6 +40,7 @@ static void handle_dhcp(void *ctx, const int res, msgtype = 0, prefixlen = 32; u32 subnet_mask = 0; u16 ip_len; + int ubus_resp; exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten)); if (exten_len < 4) @@ -112,6 +113,19 @@ static void handle_dhcp(void *ctx, const ipaddr_str(be_to_host32(b->your_ip)), prefixlen); + struct hostapd_ubus_request req = { + .type = HOSTAPD_UBUS_IP_REQ, + .sta = sta, + .ipaddr = be_to_host32(b->your_ip) + }; + ubus_resp = hostapd_ubus_handle_rt_event(hapd, &req); + if (ubus_resp) { + hostapd_logger( + hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, + "hostapd_ubus_handle_rt_event: ERROR"); + } + if (sta->ipaddr == b->your_ip) return;