Add station tracking based on other management frame subtypes
[mech_eap.git] / src / ap / beacon.c
index 98d6832..5fe8fd5 100644 (file)
@@ -552,6 +552,102 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
 }
 
 
+void sta_track_expire(struct hostapd_iface *iface, int force)
+{
+       struct os_reltime now;
+       struct hostapd_sta_info *info;
+
+       if (!iface->num_sta_seen)
+               return;
+
+       os_get_reltime(&now);
+       while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
+                                    list))) {
+               if (!force &&
+                   !os_reltime_expired(&now, &info->last_seen,
+                                       iface->conf->track_sta_max_age))
+                       break;
+               force = 0;
+
+               wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
+                          MACSTR, iface->bss[0]->conf->iface,
+                          MAC2STR(info->addr));
+               dl_list_del(&info->list);
+               iface->num_sta_seen--;
+               os_free(info);
+       }
+}
+
+
+static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
+                                              const u8 *addr)
+{
+       struct hostapd_sta_info *info;
+
+       dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
+               if (os_memcmp(addr, info->addr, ETH_ALEN) == 0)
+                       return info;
+
+       return NULL;
+}
+
+
+void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
+{
+       struct hostapd_sta_info *info;
+
+       info = sta_track_get(iface, addr);
+       if (info) {
+               /* Move the most recent entry to the end of the list */
+               dl_list_del(&info->list);
+               dl_list_add_tail(&iface->sta_seen, &info->list);
+               os_get_reltime(&info->last_seen);
+               return;
+       }
+
+       /* Add a new entry */
+       info = os_zalloc(sizeof(*info));
+       os_memcpy(info->addr, addr, ETH_ALEN);
+       os_get_reltime(&info->last_seen);
+
+       if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
+               /* Expire oldest entry to make room for a new one */
+               sta_track_expire(iface, 1);
+       }
+
+       wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
+                  MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
+       dl_list_add_tail(&iface->sta_seen, &info->list);
+       iface->num_sta_seen++;
+}
+
+
+struct hostapd_data *
+sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
+                 const char *ifname)
+{
+       struct hapd_interfaces *interfaces = iface->interfaces;
+       size_t i, j;
+
+       for (i = 0; i < interfaces->count; i++) {
+               struct hostapd_data *hapd = NULL;
+
+               iface = interfaces->iface[i];
+               for (j = 0; j < iface->num_bss; j++) {
+                       hapd = iface->bss[j];
+                       if (os_strcmp(ifname, hapd->conf->iface) == 0)
+                               break;
+                       hapd = NULL;
+               }
+
+               if (hapd && sta_track_get(iface, addr))
+                       return hapd;
+       }
+
+       return NULL;
+}
+
+
 void handle_probe_req(struct hostapd_data *hapd,
                      const struct ieee80211_mgmt *mgmt, size_t len,
                      int ssi_signal)
@@ -567,6 +663,8 @@ void handle_probe_req(struct hostapd_data *hapd,
        ie = mgmt->u.probe_req.variable;
        if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
                return;
+       if (hapd->iconf->track_sta_max_num)
+               sta_track_add(hapd->iface, mgmt->sa);
        ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
 
        for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
@@ -715,6 +813,18 @@ void handle_probe_req(struct hostapd_data *hapd,
        /* TODO: verify that supp_rates contains at least one matching rate
         * with AP configuration */
 
+       if (hapd->conf->no_probe_resp_if_seen_on &&
+           is_multicast_ether_addr(mgmt->da) &&
+           is_multicast_ether_addr(mgmt->bssid) &&
+           sta_track_seen_on(hapd->iface, mgmt->sa,
+                             hapd->conf->no_probe_resp_if_seen_on)) {
+               wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
+                          " since STA has been seen on %s",
+                          hapd->conf->iface, MAC2STR(mgmt->sa),
+                          hapd->conf->no_probe_resp_if_seen_on);
+               return;
+       }
+
 #ifdef CONFIG_TESTING_OPTIONS
        if (hapd->iconf->ignore_probe_probability > 0.0 &&
            drand48() < hapd->iconf->ignore_probe_probability) {