/*
* 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
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_ping_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,
#ifdef CONFIG_IEEE80211N
if (sta->flags & WLAN_STA_HT) {
- if ((sta->ht_capabilities.data.capabilities_info &
- HT_CAP_INFO_GREEN_FIELD) == 0)
+ u16 ht_capab = le_to_host16(
+ sta->ht_capabilities.data.capabilities_info);
+ if ((ht_capab & 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)
+ if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0)
hapd->iface->num_sta_ht_20mhz--;
} else
hapd->iface->num_sta_no_ht--;
os_free(sta->last_assoc_req);
os_free(sta->challenge);
+
+#ifdef CONFIG_IEEE80211W
+ os_free(sta->ping_trans_id);
+ eloop_cancel_timeout(ap_ping_timer, hapd, sta);
+#endif /* CONFIG_IEEE80211W */
+
+ wpabuf_free(sta->wps_ie);
+
os_free(sta);
}
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));
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,
return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
}
+
+
+#ifdef CONFIG_IEEE80211W
+
+/* MLME-PING.request */
+static void ieee802_11_send_ping_req(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *trans_id)
+{
+ struct ieee80211_mgmt mgmt;
+ u8 *end;
+
+ os_memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ os_memcpy(mgmt.da, addr, ETH_ALEN);
+ os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+ mgmt.u.action.category = WLAN_ACTION_PING;
+ mgmt.u.action.u.ping_req.action = WLAN_PING_REQUEST;
+ os_memcpy(mgmt.u.action.u.ping_req.trans_id, trans_id,
+ WLAN_PING_TRANS_ID_LEN);
+ end = mgmt.u.action.u.ping_req.trans_id + WLAN_PING_TRANS_ID_LEN;
+ if (hostapd_send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN +
+ end - (u8 *) &mgmt, 0) < 0)
+ perror("ieee802_11_send_ping_req: send");
+}
+
+
+static void ap_ping_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->ping_count >= hapd->conf->assoc_ping_attempts) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "association ping timed out");
+ sta->ping_timed_out = 1;
+ os_free(sta->ping_trans_id);
+ sta->ping_trans_id = NULL;
+ sta->ping_count = 0;
+ return;
+ }
+
+ nbuf = os_realloc(sta->ping_trans_id,
+ (sta->ping_count + 1) * WLAN_PING_TRANS_ID_LEN);
+ if (nbuf == NULL)
+ return;
+ trans_id = nbuf + sta->ping_count * WLAN_PING_TRANS_ID_LEN;
+ sta->ping_trans_id = nbuf;
+ sta->ping_count++;
+
+ os_get_random(trans_id, WLAN_PING_TRANS_ID_LEN);
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "association ping attempt %d", sta->ping_count);
+
+ ieee802_11_send_ping_req(hapd, sta->addr, trans_id);
+
+ timeout = hapd->conf->assoc_ping_timeout;
+ sec = ((timeout / 1000) * 1024) / 1000;
+ usec = (timeout % 1000) * 1024;
+ eloop_register_timeout(sec, usec, ap_ping_timer, hapd, sta);
+}
+
+
+void ap_sta_start_ping(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ ap_ping_timer(hapd, sta);
+}
+
+
+void ap_sta_stop_ping(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ eloop_cancel_timeout(ap_ping_timer, hapd, sta);
+ os_free(sta->ping_trans_id);
+ sta->ping_trans_id = NULL;
+ sta->ping_count = 0;
+}
+
+#endif /* CONFIG_IEEE80211W */