if (hapd->p2p_probe_resp_ie)
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies)
+ buflen += wpabuf_len(hapd->iface->fst_ies);
+#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
if (hapd->conf->vendor_vht) {
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
&hapd->cs_c_off_proberesp);
+
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies) {
+ os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
+ wpabuf_len(hapd->iface->fst_ies));
+ pos += wpabuf_len(hapd->iface->fst_ies);
+ }
+#endif /* CONFIG_FST */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
pos = hostapd_eid_vht_capabilities(hapd, pos);
}
+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)
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++)
/* 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) {
if (hapd->p2p_beacon_ie)
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
#endif /* CONFIG_P2P */
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies)
+ tail_len += wpabuf_len(hapd->iface->fst_ies);
+#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
&hapd->cs_c_off_beacon);
+
+#ifdef CONFIG_FST
+ if (hapd->iface->fst_ies) {
+ os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
+ wpabuf_len(hapd->iface->fst_ies));
+ tailpos += wpabuf_len(hapd->iface->fst_ies);
+ }
+#endif /* CONFIG_FST */
+
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
params->basic_rates = hapd->iface->basic_rates;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
- params->pairwise_ciphers = hapd->conf->wpa_pairwise |
- hapd->conf->rsn_pairwise;
+ if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
+ (WPA_PROTO_WPA | WPA_PROTO_RSN))
+ params->pairwise_ciphers = hapd->conf->wpa_pairwise |
+ hapd->conf->rsn_pairwise;
+ else if (hapd->conf->wpa & WPA_PROTO_RSN)
+ params->pairwise_ciphers = hapd->conf->rsn_pairwise;
+ else if (hapd->conf->wpa & WPA_PROTO_WPA)
+ params->pairwise_ciphers = hapd->conf->wpa_pairwise;
params->group_cipher = hapd->conf->wpa_group;
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;