diff options
author | sam <sam@FreeBSD.org> | 2007-07-09 16:15:06 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2007-07-09 16:15:06 +0000 |
commit | 1bf2fd00c50865c26197a0fb9ce70f417b9fa121 (patch) | |
tree | c6f336fc28b042f00efc2373c71fceadfa394e52 /contrib/hostapd/sta_info.c | |
parent | 620bfba12034be7d2ad4a357063d609ff5b6e63a (diff) | |
download | FreeBSD-src-1bf2fd00c50865c26197a0fb9ce70f417b9fa121.zip FreeBSD-src-1bf2fd00c50865c26197a0fb9ce70f417b9fa121.tar.gz |
Import of hostapd 0.5.8
Diffstat (limited to 'contrib/hostapd/sta_info.c')
-rw-r--r-- | contrib/hostapd/sta_info.c | 298 |
1 files changed, 264 insertions, 34 deletions
diff --git a/contrib/hostapd/sta_info.c b/contrib/hostapd/sta_info.c index 9eb0bca..dbb7f6c 100644 --- a/contrib/hostapd/sta_info.c +++ b/contrib/hostapd/sta_info.c @@ -1,7 +1,6 @@ /* - * Host AP (software wireless LAN access point) user space daemon for - * Host AP kernel driver / Station table - * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi> + * hostapd / Station table + * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi> * * 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 @@ -13,12 +12,7 @@ * See README and COPYING for more details. */ -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <netinet/in.h> -#include <sys/types.h> -#include <sys/socket.h> +#include "includes.h" #include "hostapd.h" #include "sta_info.h" @@ -29,10 +23,17 @@ #include "radius.h" #include "eapol_sm.h" #include "wpa.h" +#include "preauth.h" #include "radius_client.h" #include "driver.h" -#include "hostap_common.h" +#include "beacon.h" +#include "hw_features.h" +#include "mlme.h" +#include "vlan_init.h" +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); int ap_for_each_sta(struct hostapd_data *hapd, int (*cb)(struct hostapd_data *hapd, struct sta_info *sta, @@ -61,7 +62,7 @@ struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta) } -static void ap_sta_list_del(hostapd *hapd, struct sta_info *sta) +static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta) { struct sta_info *tmp; @@ -81,14 +82,14 @@ static void ap_sta_list_del(hostapd *hapd, struct sta_info *sta) } -void ap_sta_hash_add(hostapd *hapd, struct sta_info *sta) +void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta) { sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)]; hapd->sta_hash[STA_HASH(sta->addr)] = sta; } -static void ap_sta_hash_del(hostapd *hapd, struct sta_info *sta) +static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta) { struct sta_info *s; @@ -109,10 +110,14 @@ static void ap_sta_hash_del(hostapd *hapd, struct sta_info *sta) } -void ap_free_sta(hostapd *hapd, struct sta_info *sta) +void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) { + int set_beacon = 0; + accounting_sta_stop(hapd, sta); - if (!(sta->flags & WLAN_STA_PREAUTH)) + + if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) && + !(sta->flags & WLAN_STA_PREAUTH)) hostapd_sta_remove(hapd, sta->addr); ap_sta_hash_del(hapd, sta); @@ -122,23 +127,50 @@ void ap_free_sta(hostapd *hapd, struct sta_info *sta) hapd->sta_aid[sta->aid - 1] = NULL; hapd->num_sta--; + if (sta->nonerp_set) { + sta->nonerp_set = 0; + hapd->iface->num_sta_non_erp--; + if (hapd->iface->num_sta_non_erp == 0) + set_beacon++; + } + + if (sta->no_short_slot_time_set) { + sta->no_short_slot_time_set = 0; + hapd->iface->num_sta_no_short_slot_time--; + if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G + && hapd->iface->num_sta_no_short_slot_time == 0) + set_beacon++; + } + + if (sta->no_short_preamble_set) { + sta->no_short_preamble_set = 0; + hapd->iface->num_sta_no_short_preamble--; + if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G + && hapd->iface->num_sta_no_short_preamble == 0) + set_beacon++; + } + + if (set_beacon) + ieee802_11_set_beacons(hapd->iface); + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); ieee802_1x_free_station(sta); - wpa_free_station(sta); + wpa_auth_sta_deinit(sta->wpa_sm); + rsn_preauth_free_station(hapd, sta); radius_client_flush_auth(hapd->radius, sta->addr); if (sta->last_assoc_req) free(sta->last_assoc_req); free(sta->challenge); - free(sta->wpa_ie); free(sta); } -void hostapd_free_stas(hostapd *hapd) +void hostapd_free_stas(struct hostapd_data *hapd) { struct sta_info *sta, *prev; @@ -146,6 +178,10 @@ void hostapd_free_stas(hostapd *hapd) while (sta) { prev = sta; + if (sta->flags & WLAN_STA_AUTH) { + mlme_deauthenticate_indication( + hapd, sta, WLAN_REASON_UNSPECIFIED); + } sta = sta->next; printf("Removing station " MACSTR "\n", MAC2STR(prev->addr)); ap_free_sta(hapd, prev); @@ -155,7 +191,7 @@ void hostapd_free_stas(hostapd *hapd) void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) { - hostapd *hapd = eloop_ctx; + struct hostapd_data *hapd = eloop_ctx; struct sta_info *sta = timeout_ctx; unsigned long next_time = 0; @@ -179,13 +215,14 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) printf(" Could not get station info from kernel " "driver for " MACSTR ".\n", MAC2STR(sta->addr)); - } else if (inactive_sec < AP_MAX_INACTIVITY && + } else if (inactive_sec < hapd->conf->ap_max_inactivity && sta->flags & WLAN_STA_ASSOC) { /* station activity detected; reset timeout state */ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " Station has been active\n"); sta->timeout_next = STA_NULLFUNC; - next_time = AP_MAX_INACTIVITY - inactive_sec; + next_time = hapd->conf->ap_max_inactivity - + inactive_sec; } } @@ -197,7 +234,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) /* data nullfunc frame poll did not produce TX errors; assume * station ACKed it */ sta->timeout_next = STA_NULLFUNC; - next_time = AP_MAX_INACTIVITY; + next_time = hapd->conf->ap_max_inactivity; } if (next_time) { @@ -216,6 +253,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) " Polling STA with data frame\n"); 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 */ @@ -230,6 +268,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0) perror("ap_handle_timer: send"); +#endif /* CONFIG_NATIVE_WINDOWS */ } else if (sta->timeout_next != STA_REMOVE) { int deauth = sta->timeout_next == STA_DEAUTH; @@ -255,7 +294,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) break; case STA_DISASSOC: sta->flags &= ~WLAN_STA_ASSOC; - ieee802_1x_set_port_enabled(hapd, sta, 0); + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); if (!sta->acct_terminate_cause) sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; @@ -267,6 +306,8 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) sta->timeout_next = STA_DEAUTH; eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, hapd, sta); + mlme_disassociate_indication( + hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); break; case STA_DEAUTH: case STA_REMOVE: @@ -276,31 +317,38 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) if (!sta->acct_terminate_cause) sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; + mlme_deauthenticate_indication( + hapd, sta, + WLAN_REASON_PREV_AUTH_NOT_VALID); ap_free_sta(hapd, sta); break; } } -void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) +static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) { - hostapd *hapd = eloop_ctx; + struct hostapd_data *hapd = eloop_ctx; struct sta_info *sta = timeout_ctx; + u8 addr[ETH_ALEN]; if (!(sta->flags & WLAN_STA_AUTH)) return; - hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); + mlme_deauthenticate_indication(hapd, sta, + WLAN_REASON_PREV_AUTH_NOT_VALID); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " "session timeout"); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT; + memcpy(addr, sta->addr, ETH_ALEN); ap_free_sta(hapd, sta); + hostapd_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID); } -void ap_sta_session_timeout(hostapd *hapd, struct sta_info *sta, +void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta, u32 session_timeout) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, @@ -312,7 +360,7 @@ void ap_sta_session_timeout(hostapd *hapd, struct sta_info *sta, } -void ap_sta_no_session_timeout(hostapd *hapd, struct sta_info *sta) +void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta) { eloop_cancel_timeout(ap_handle_session_timer, hapd, sta); } @@ -327,29 +375,211 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr) return sta; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " New STA\n"); - if (hapd->num_sta >= MAX_STA_COUNT) { + if (hapd->num_sta >= hapd->conf->max_num_sta) { /* FIX: might try to remove some old STAs first? */ printf(" no more room for new STAs (%d/%d)\n", - hapd->num_sta, MAX_STA_COUNT); + hapd->num_sta, hapd->conf->max_num_sta); return NULL; } - sta = (struct sta_info *) malloc(sizeof(struct sta_info)); + sta = wpa_zalloc(sizeof(struct sta_info)); if (sta == NULL) { printf(" malloc failed\n"); return NULL; } - memset(sta, 0, sizeof(struct sta_info)); sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval; /* initialize STA info data */ - eloop_register_timeout(AP_MAX_INACTIVITY, 0, ap_handle_timer, - hapd, sta); + eloop_register_timeout(hapd->conf->ap_max_inactivity, 0, + ap_handle_timer, hapd, sta); memcpy(sta->addr, addr, ETH_ALEN); sta->next = hapd->sta_list; hapd->sta_list = sta; hapd->num_sta++; ap_sta_hash_add(hapd, sta); + sta->ssid = &hapd->conf->ssid; return sta; } + + +static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta) +{ + ieee802_1x_notify_port_enabled(sta->eapol_sm, 0); + + HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Removing STA " MACSTR + " from kernel driver\n", MAC2STR(sta->addr)); + if (hostapd_sta_remove(hapd, sta->addr) && + sta->flags & WLAN_STA_ASSOC) { + printf("Could not remove station " MACSTR " from kernel " + "driver.\n", MAC2STR(sta->addr)); + return -1; + } + return 0; +} + + +static int ap_sta_in_other_bss(struct hostapd_data *hapd, + struct sta_info *sta, u32 flags) +{ + struct hostapd_iface *iface = hapd->iface; + size_t i; + + for (i = 0; i < iface->num_bss; i++) { + struct hostapd_data *bss = iface->bss[i]; + struct sta_info *sta2; + /* bss should always be set during operation, but it may be + * NULL during reconfiguration. Assume the STA is not + * associated to another BSS in that case to avoid NULL pointer + * dereferences. */ + if (bss == hapd || bss == NULL) + continue; + sta2 = ap_get_sta(bss, sta->addr); + if (sta2 && ((sta2->flags & flags) == flags)) + return 1; + } + + return 0; +} + + +void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason) +{ + HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: disassociate STA " MACSTR + "\n", hapd->conf->iface, MAC2STR(sta->addr)); + sta->flags &= ~WLAN_STA_ASSOC; + if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC)) + ap_sta_remove(hapd, sta); + sta->timeout_next = STA_DEAUTH; + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0, + ap_handle_timer, hapd, sta); + accounting_sta_stop(hapd, sta); + ieee802_1x_free_station(sta); + + mlme_disassociate_indication(hapd, sta, reason); +} + + +void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta, + u16 reason) +{ + HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: deauthenticate STA " MACSTR + "\n", hapd->conf->iface, MAC2STR(sta->addr)); + sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); + if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC)) + ap_sta_remove(hapd, sta); + sta->timeout_next = STA_REMOVE; + eloop_cancel_timeout(ap_handle_timer, hapd, sta); + eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0, + ap_handle_timer, hapd, sta); + accounting_sta_stop(hapd, sta); + ieee802_1x_free_station(sta); + + mlme_deauthenticate_indication(hapd, sta, reason); +} + + +int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta, + int old_vlanid) +{ + const char *iface; + struct hostapd_vlan *vlan = NULL; + + /* + * Do not proceed furthur if the vlan id remains same. We do not want + * duplicate dynamic vlan entries. + */ + if (sta->vlan_id == old_vlanid) + return 0; + + /* + * During 1x reauth, if the vlan id changes, then remove the old id and + * proceed furthur to add the new one. + */ + if (old_vlanid > 0) + vlan_remove_dynamic(hapd, old_vlanid); + + iface = hapd->conf->iface; + if (sta->ssid->vlan[0]) + iface = sta->ssid->vlan; + + if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED) + sta->vlan_id = 0; + else if (sta->vlan_id > 0) { + vlan = hapd->conf->vlan; + while (vlan) { + if (vlan->vlan_id == sta->vlan_id || + vlan->vlan_id == VLAN_ID_WILDCARD) { + iface = vlan->ifname; + break; + } + vlan = vlan->next; + } + } + + if (sta->vlan_id > 0 && vlan == NULL) { + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "could not find VLAN for " + "binding station to (vlan_id=%d)", + sta->vlan_id); + return -1; + } else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) { + vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id); + if (vlan == NULL) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "could not add " + "dynamic VLAN interface for vlan_id=%d", + sta->vlan_id); + return -1; + } + + iface = vlan->ifname; + if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "could not " + "configure encryption for dynamic VLAN " + "interface for vlan_id=%d", + sta->vlan_id); + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN " + "interface '%s'", iface); + } else if (vlan && vlan->vlan_id == sta->vlan_id) { + if (sta->vlan_id > 0) { + vlan->dynamic_vlan++; + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "updated existing " + "dynamic VLAN interface '%s'", iface); + } + + /* + * Update encryption configuration for statically generated + * VLAN interface. This is only used for static WEP + * configuration for the case where hostapd did not yet know + * which keys are to be used when the interface was added. + */ + if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) { + hostapd_logger(hapd, sta->addr, + HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "could not " + "configure encryption for VLAN " + "interface for vlan_id=%d", + sta->vlan_id); + } + } + + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_DEBUG, "binding station to interface " + "'%s'", iface); + + if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0) + wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA"); + + return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id); +} |