With FT-over-air, the station sends an authentication request which is subject to macaddr_acl (RADIUS) in src/ieee802_11.c. But with FT-over-DS, the authentication request is replaced by an FT-action frame and FT inter-AP messages, which are not subject to any macaddr_acl logic. This patch fixes this by adopting macaddr_acl processing for FT over DS. This ensures session_timeout, radius accounting configuration and alike. In order to correctly handle this, a new sta flag is introduced. Therefore, sta->flags is converted to u64. Though, the BIT marcro only works for <32bit (https://gcc.gnu.org/ml/gcc/1999-09n/msg00860.html). Signed-off-by: Michael Braun <michael-dev@xxxxxxxxxxxxx> --- src/ap/ieee802_11.c | 12 +++++--- src/ap/sta_info.c | 5 +++- src/ap/sta_info.h | 3 +- src/ap/wpa_auth.h | 7 ++++- src/ap/wpa_auth_ft.c | 67 +++++++++++++++++++++++++++++++++++++------ src/ap/wpa_auth_glue.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 153 insertions(+), 18 deletions(-) diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index caa05ad..d0a7029 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1008,11 +1008,13 @@ int handle_auth_cfg_sta(struct hostapd_data *hapd, struct sta_info *sta, "Invalid VLAN %d%s received from RADIUS server", info->vlan_id.untagged, info->vlan_id.tagged[0] ? "+" : ""); - *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + if (resp) + *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; return -1; } if (ap_sta_set_vlan(hapd, sta, &info->vlan_id) < 0) { - *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; + if (resp) + *resp = WLAN_STATUS_UNSPECIFIED_FAILURE; return -1; } if (sta->vlan_id) @@ -2148,7 +2150,8 @@ static void handle_assoc(struct hostapd_data *hapd, sta = ap_get_sta(hapd, mgmt->sa); #ifdef CONFIG_IEEE80211R if (sta && sta->auth_alg == WLAN_AUTH_FT && - (sta->flags & WLAN_STA_AUTH) == 0) { + (sta->flags & WLAN_STA_AUTH) == 0 && + (sta->flags & WLAN_STA_PREAUTH_FT_OVER_DS)) { wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate " "prior to authentication since it is using " "over-the-DS FT", MAC2STR(mgmt->sa)); @@ -2164,7 +2167,7 @@ static void handle_assoc(struct hostapd_data *hapd, hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "Station tried to " "associate before authentication " - "(aid=%d flags=0x%x)", + "(aid=%d flags=0x%lx)", sta ? sta->aid : -1, sta ? sta->flags : 0); send_deauth(hapd, mgmt->sa, @@ -2875,6 +2878,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; + sta->flags &= ~WLAN_STA_PREAUTH_FT_OVER_DS; if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa && !hapd->conf->osen) || sta->auth_alg == WLAN_AUTH_FT) { /* diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index f12d408..b508afb 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -376,7 +376,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) unsigned long next_time = 0; int reason; - wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d", + wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%lx timeout_next=%d", hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags, sta->timeout_next); if (sta->timeout_next == STA_REMOVE) { @@ -543,6 +543,9 @@ static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx) wpa_printf(MSG_DEBUG, "%s: Session timer for STA " MACSTR, hapd->conf->iface, MAC2STR(sta->addr)); + + sta->flags &= ~WLAN_STA_PREAUTH_FT_OVER_DS; + if (!(sta->flags & WLAN_STA_AUTH)) { if (sta->flags & WLAN_STA_GAS) { wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA " diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index d0e43be..29043a6 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -41,6 +41,7 @@ #define WLAN_STA_PENDING_DISASSOC_CB BIT(29) #define WLAN_STA_PENDING_DEAUTH_CB BIT(30) #define WLAN_STA_NONERP BIT(31) +#define WLAN_STA_PREAUTH_FT_OVER_DS (((u64) 1) << 32) /* Maximum number of supported rates (from both Supported Rates and Extended * Supported Rates IEs). */ @@ -69,7 +70,7 @@ struct sta_info { be32 ipaddr; struct dl_list ip6addr; /* list head for struct ip6addr */ u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */ - u32 flags; /* Bitfield of WLAN_STA_* */ + u64 flags; /* Bitfield of WLAN_STA_* */ u16 capability; u16 listen_interval; /* or beacon_int for APs */ u8 supported_rates[WLAN_SUPP_RATES_MAX]; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index 3c454ce..127ae60 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -223,7 +223,12 @@ struct wpa_auth_callbacks { int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data, size_t data_len); #ifdef CONFIG_IEEE80211R - struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr); + int (*add_sta)(void *ctx, const u8 *sta_addr, + struct wpa_state_machine **sm, + void (*cb)(void *ctx, const u8 *buf, size_t len, + const u8 *mac, int accepted, + u32 session_timeout), + void *cb_ctx, int cb_ctx_len); int (*set_vlan)(void *ctx, const u8 *sta_addr, struct vlan_description *vlan); int (*get_vlan)(void *ctx, const u8 *sta_addr, diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index 86e6a27..7530196 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -24,6 +24,9 @@ #ifdef CONFIG_IEEE80211R +static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, + const u8 *current_ap, const u8 *sta_addr, + const u8 *body, size_t len); static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm, const u8 *current_ap, const u8 *sta_addr, u16 status, const u8 *resp_ies, @@ -457,12 +460,19 @@ static inline const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth, } -static struct wpa_state_machine * -wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr) +static int +wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr, + struct wpa_state_machine **sm, + void (*cb)(void *hapd, const u8 *buf, size_t len, + const u8 *mac, int accepted, u32 session_timeout), + void *cb_ctx, int cb_ctx_len) { - if (wpa_auth->cb.add_sta == NULL) - return NULL; - return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr); + if (wpa_auth->cb.add_sta == NULL) { + *sm = NULL; + return 0; + } + return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr, sm, cb, cb_ctx, + cb_ctx_len); } @@ -2032,21 +2042,62 @@ static void wpa_ft_rrb_rx_request_cb(void *ctx, const u8 *dst, const u8 *bssid, wpa_printf(MSG_DEBUG, "FT: Over-the-DS RX request cb for " MACSTR, MAC2STR(sm->addr)); wpa_ft_send_rrb_auth_resp(sm, sm->ft_pending_current_ap, sm->addr, - WLAN_STATUS_SUCCESS, ies, ies_len); + resp, ies, ies_len); } +struct wpa_ft_rrb_rx_request_restart_ctx { + struct wpa_authenticator *wpa_auth; + u8 current_ap[ETH_ALEN]; + u8 sta_addr[ETH_ALEN]; + u8 buf[]; +}; + + +static void +wpa_ft_rrb_rx_request_restart_cb(void *hapd, const u8 *buf, + size_t len, const u8 *mac, int accepted, + u32 session_timeout) +{ + struct wpa_ft_rrb_rx_request_restart_ctx *ctx; + + ctx = (struct wpa_ft_rrb_rx_request_restart_ctx *) buf; + wpa_ft_rrb_rx_request(ctx->wpa_auth, ctx->current_ap, ctx->sta_addr, + ctx->buf, len - sizeof(*ctx)); +} + static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth, const u8 *current_ap, const u8 *sta_addr, const u8 *body, size_t len) { - struct wpa_state_machine *sm; + struct wpa_state_machine *sm = NULL; u16 status; u8 *resp_ies; size_t resp_ies_len; int res; + struct wpa_ft_rrb_rx_request_restart_ctx *cb_ctx; + + cb_ctx = os_zalloc(sizeof(*cb_ctx) + len); + if (cb_ctx == NULL) { + wpa_printf(MSG_DEBUG, "FT: Failed to allocate " + "wpa_ft_rrb_rx_request_restart_ctx"); + return -1; + } + + cb_ctx->wpa_auth = wpa_auth; + os_memcpy(cb_ctx->current_ap, current_ap, ETH_ALEN); + os_memcpy(cb_ctx->sta_addr, sta_addr, ETH_ALEN); + os_memcpy(cb_ctx->buf, body, len); - sm = wpa_ft_add_sta(wpa_auth, sta_addr); + res = wpa_ft_add_sta(wpa_auth, sta_addr, &sm, + &wpa_ft_rrb_rx_request_restart_cb, cb_ctx, + sizeof(*cb_ctx) + len); + os_free(cb_ctx); cb_ctx = NULL; + if (res < 0) { + wpa_printf(MSG_DEBUG, "FT: No immediate response available - " + "wait for macaddr_acl response"); + return 0; + } if (sm == NULL) { wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on " "RRB Request"); diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index c29086a..fd1c4aa 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -19,6 +19,8 @@ #include "l2_packet/l2_packet.h" #include "hostapd.h" #include "ieee802_1x.h" +#include "ieee802_11_auth.h" +#include "ieee802_11.h" #include "preauth_auth.h" #include "sta_info.h" #include "tkip_countermeasures.h" @@ -547,9 +549,8 @@ static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst, static struct wpa_state_machine * -hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) +hostapd_wpa_auth_add_sta(struct hostapd_data *hapd, const u8 *sta_addr) { - struct hostapd_data *hapd = ctx; struct sta_info *sta; if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0) @@ -574,6 +575,76 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr) } +static int +hostapd_wpa_auth_add_sta_auth(void *ctx, const u8 *sta_addr, + struct wpa_state_machine **sm, + void (*cb)(void *hapd, const u8 *buf, size_t len, + const u8 *mac, int accepted, + u32 session_timeout), + void *cb_ctx, int cb_ctx_len) +{ + struct hostapd_data *hapd = ctx; + struct sta_info *sta = NULL; + int res = 0; + void (*cb2)(struct hostapd_data *hapd, const u8 *buf, size_t len, + const u8 *mac, int accepted, u32 session_timeout); + struct hostapd_allowed_address_info info; + + hostapd_allowed_address_init(&info); + cb2 = (void (*) (struct hostapd_data *hapd, const u8 *buf, size_t len, + const u8 *mac, int accepted, u32 session_timeout)) cb; + + if (os_memcmp(sta_addr, hapd->own_addr, ETH_ALEN) == 0) { + wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to " + "authenticate", MAC2STR(sta_addr)); + *sm = NULL; + return 0; + } + + *sm = hostapd_wpa_auth_add_sta(hapd, sta_addr); + if (!*sm) + return 0; + + res = hostapd_allowed_address(hapd, sta_addr, (u8 *) cb_ctx, + cb_ctx_len, cb2, &info); + + if (res == HOSTAPD_ACL_REJECT) { + wpa_printf(MSG_INFO, "Station " MACSTR " not allowed to " + "authenticate", MAC2STR(sta_addr)); + goto fail; + } + if (res == HOSTAPD_ACL_PENDING) { + wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR + " waiting for an external authentication", + MAC2STR(sta_addr)); + /* Authentication code will re-send the authentication frame + * after it has received (and cached) information from the + * external source. + */ + res = -1; + goto fail; + } + + sta = ap_get_sta(hapd, sta_addr); + if (!sta) + goto fail; + + if (handle_auth_cfg_sta(hapd, sta, res, &info, NULL) < 0) + goto fail; + + sta->flags &= ~WLAN_STA_PREAUTH; + sta->flags |= WLAN_STA_PREAUTH_FT_OVER_DS; + + ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); + + return 0; +fail: + hostapd_allowed_address_free(&info); + *sm = NULL; + + return res; +} + static int hostapd_wpa_auth_set_vlan(void *ctx, const u8 *sta_addr, struct vlan_description *vlan) @@ -691,7 +762,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd) cb.send_ether = hostapd_wpa_auth_send_ether; #ifdef CONFIG_IEEE80211R cb.send_ft_action = hostapd_wpa_auth_send_ft_action; - cb.add_sta = hostapd_wpa_auth_add_sta; + cb.add_sta = hostapd_wpa_auth_add_sta_auth; cb.set_vlan = hostapd_wpa_auth_set_vlan; cb.get_vlan = hostapd_wpa_auth_get_vlan; cb.add_tspec = hostapd_wpa_auth_add_tspec; -- 2.1.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap