Remove flags parameter from send_mgmt_frame() driver op
[wpasupplicant] / hostapd / sta_info.c
index 7bc7fae..7a22e92 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,7 +25,7 @@
 #include "wpa.h"
 #include "preauth.h"
 #include "radius/radius_client.h"
-#include "driver.h"
+#include "driver_i.h"
 #include "beacon.h"
 #include "hw_features.h"
 #include "mlme.h"
@@ -33,6 +34,9 @@
 static int ap_sta_in_other_bss(struct hostapd_data *hapd,
                               struct sta_info *sta, u32 flags);
 static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_IEEE80211W
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_IEEE80211W */
 
 int ap_for_each_sta(struct hostapd_data *hapd,
                    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -124,7 +128,8 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        ap_sta_list_del(hapd, sta);
 
        if (sta->aid > 0)
-               hapd->sta_aid[sta->aid - 1] = NULL;
+               hapd->sta_aid[(sta->aid - 1) / 32] &=
+                       ~BIT((sta->aid - 1) % 32);
 
        hapd->num_sta--;
        if (sta->nonerp_set) {
@@ -151,18 +156,25 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
        }
 
 #ifdef CONFIG_IEEE80211N
-       if (sta->flags & WLAN_STA_HT) {
-               if ((sta->ht_capabilities.data.capabilities_info &
-                    HT_CAP_INFO_GREEN_FIELD) == 0)
-                       hapd->iface->num_sta_ht_no_gf--;
-               if ((sta->ht_capabilities.data.capabilities_info &
-                    HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0)
-                       hapd->iface->num_sta_ht_20mhz--;
-       } else
+       if (sta->no_ht_gf_set) {
+               sta->no_ht_gf_set = 0;
+               hapd->iface->num_sta_ht_no_gf--;
+       }
+
+       if (sta->no_ht_set) {
+               sta->no_ht_set = 0;
                hapd->iface->num_sta_no_ht--;
+       }
+
+       if (sta->ht_20mhz_set) {
+               sta->ht_20mhz_set = 0;
+               hapd->iface->num_sta_ht_20mhz--;
+       }
 
+#ifdef NEED_MLME
        if (hostapd_ht_operation_update(hapd->iface) > 0)
                set_beacon++;
+#endif /* NEED_MLME */
 #endif /* CONFIG_IEEE80211N */
 
        if (set_beacon)
@@ -178,6 +190,14 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 
        os_free(sta->last_assoc_req);
        os_free(sta->challenge);
+
+#ifdef CONFIG_IEEE80211W
+       os_free(sta->sa_query_trans_id);
+       eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+#endif /* CONFIG_IEEE80211W */
+
+       wpabuf_free(sta->wps_ie);
+
        os_free(sta);
 }
 
@@ -202,6 +222,14 @@ void hostapd_free_stas(struct hostapd_data *hapd)
 }
 
 
+/**
+ * ap_handle_timer - Per STA timer handler
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: struct sta_info *
+ *
+ * This function is called to check station activity and to remove inactive
+ * stations.
+ */
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
 {
        struct hostapd_data *hapd = eloop_ctx;
@@ -263,20 +291,30 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                sta->flags |= WLAN_STA_PENDING_POLL;
 
 #ifndef CONFIG_NATIVE_WINDOWS
-               /* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
-                * it is apparently not retried so TX Exc events are not
-                * received for it */
                os_memset(&hdr, 0, sizeof(hdr));
-               hdr.frame_control =
-                       IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
-               hdr.frame_control |= host_to_le16(BIT(1));
+               if (hapd->driver &&
+                   os_strcmp(hapd->driver->name, "hostap") == 0) {
+                       /*
+                        * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+                        * but it is apparently not retried so TX Exc events
+                        * are not received for it.
+                        */
+                       hdr.frame_control =
+                               IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                            WLAN_FC_STYPE_DATA);
+               } else {
+                       hdr.frame_control =
+                               IEEE80211_FC(WLAN_FC_TYPE_DATA,
+                                            WLAN_FC_STYPE_NULLFUNC);
+               }
+
                hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
                os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
                os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
                          ETH_ALEN);
                os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
 
-               if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0)
+               if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr)) < 0)
                        perror("ap_handle_timer: send");
 #endif /* CONFIG_NATIVE_WINDOWS */
        } else if (sta->timeout_next != STA_REMOVE) {
@@ -494,6 +532,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
 int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
                     int old_vlanid)
 {
+#ifndef CONFIG_NO_VLAN
        const char *iface;
        struct hostapd_vlan *vlan = NULL;
 
@@ -592,4 +631,90 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
                wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
 
        return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
+#else /* CONFIG_NO_VLAN */
+       return 0;
+#endif /* CONFIG_NO_VLAN */
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       u32 tu;
+       struct os_time now, passed;
+       os_get_time(&now);
+       os_time_sub(&now, &sta->sa_query_start, &passed);
+       tu = (passed.sec * 1000000 + passed.usec) / 1024;
+       if (hapd->conf->assoc_sa_query_max_timeout < tu) {
+               hostapd_logger(hapd, sta->addr,
+                              HOSTAPD_MODULE_IEEE80211,
+                              HOSTAPD_LEVEL_DEBUG,
+                              "association SA Query timed out");
+               sta->sa_query_timed_out = 1;
+               os_free(sta->sa_query_trans_id);
+               sta->sa_query_trans_id = NULL;
+               sta->sa_query_count = 0;
+               eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+               return 1;
+       }
+
+       return 0;
+}
+
+
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = timeout_ctx;
+       unsigned int timeout, sec, usec;
+       u8 *trans_id, *nbuf;
+
+       if (sta->sa_query_count > 0 &&
+           ap_check_sa_query_timeout(hapd, sta))
+               return;
+
+       nbuf = os_realloc(sta->sa_query_trans_id,
+                         (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
+       if (nbuf == NULL)
+               return;
+       if (sta->sa_query_count == 0) {
+               /* Starting a new SA Query procedure */
+               os_get_time(&sta->sa_query_start);
+       }
+       trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
+       sta->sa_query_trans_id = nbuf;
+       sta->sa_query_count++;
+
+       os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+       timeout = hapd->conf->assoc_sa_query_retry_timeout;
+       sec = ((timeout / 1000) * 1024) / 1000;
+       usec = (timeout % 1000) * 1024;
+       eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
+
+       hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+                      HOSTAPD_LEVEL_DEBUG,
+                      "association SA Query attempt %d", sta->sa_query_count);
+
+#ifdef NEED_MLME
+       ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
+#endif /* NEED_MLME */
+}
+
+
+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       ap_sa_query_timer(hapd, sta);
+}
+
+
+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+       eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+       os_free(sta->sa_query_trans_id);
+       sta->sa_query_trans_id = NULL;
+       sta->sa_query_count = 0;
 }
+
+#endif /* CONFIG_IEEE80211W */