/* This function will be called whenever a station associates with the AP */ void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta) { if (hapd->tkip_countermeasures) { hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_MICHAEL_MIC_FAILURE); return; } /* IEEE 802.11F (IAPP) */ if (hapd->conf->ieee802_11f) iapp_new_station(hapd->iapp, sta); /* Start accounting here, if IEEE 802.1X is not used. IEEE 802.1X code * will start accounting after the station has been authorized. */ if (!hapd->conf->ieee802_1x) accounting_sta_start(hapd, sta); #ifdef JUMPSTART if (hapd->conf->js_p1) { /* Only one STA at a time to attempt Jumpstart */ if (!hapd->jsw_profile->p1_in_progress) { hapd->jsw_profile->p1_in_progress = 1; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "JUMPSTART: " MACSTR " %s: starting P1\n", MAC2STR(sta->addr), __func__); js_p1_new_station(hapd, sta); /* Start the JS state machine */ smSendEvent(sta->js_session, JSW_EVENT_ASSOC); } else { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "JUMPSTART: " MACSTR "%s: P1 running with another STA." " Disassoc\n", MAC2STR(sta->addr), __func__); hostapd_sta_disassoc(hapd, sta->addr, WLAN_REASON_UNSPECIFIED); } return; } #endif /* JUMPSTART */ /* Start IEEE 802.1x authentication process for new stations */ ieee802_1x_new_station(hapd, sta); wpa_new_station(hapd, sta); }
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx) { hostapd *hapd = eloop_ctx; struct sta_info *sta = timeout_ctx; unsigned long next_time = 0; if (sta->timeout_next == STA_REMOVE) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " "local deauth request"); ap_free_sta(hapd, sta); return; } if ((sta->flags & WLAN_STA_ASSOC) && (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC)) { int inactive_sec; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Checking STA " MACSTR " inactivity:\n", MAC2STR(sta->addr)); inactive_sec = hostapd_get_inact_sec(hapd, sta->addr); if (inactive_sec == -1) { printf(" Could not get station info from kernel " "driver for " MACSTR ".\n", MAC2STR(sta->addr)); } else if (inactive_sec < 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; } } if ((sta->flags & WLAN_STA_ASSOC) && sta->timeout_next == STA_DISASSOC && !(sta->flags & WLAN_STA_PENDING_POLL)) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " Station has ACKed data poll\n"); /* data nullfunc frame poll did not produce TX errors; assume * station ACKed it */ sta->timeout_next = STA_NULLFUNC; next_time = AP_MAX_INACTIVITY; } if (next_time) { eloop_register_timeout(next_time, 0, ap_handle_timer, hapd, sta); return; } if (sta->timeout_next == STA_NULLFUNC && (sta->flags & WLAN_STA_ASSOC)) { /* send data frame to poll STA and check whether this frame * is ACKed */ struct ieee80211_hdr hdr; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, " Polling STA with data frame\n"); sta->flags |= WLAN_STA_PENDING_POLL; /* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but * it is apparently not retried so TX Exc events are not * received for it */ 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); memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN); memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr, ETH_ALEN); memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN); if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0) perror("ap_handle_timer: send"); } else if (sta->timeout_next != STA_REMOVE) { int deauth = sta->timeout_next == STA_DEAUTH; printf(" Sending %s info to STA " MACSTR "\n", deauth ? "deauthentication" : "disassociation", MAC2STR(sta->addr)); if (deauth) { hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID); } else { hostapd_sta_disassoc( hapd, sta->addr, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); } } switch (sta->timeout_next) { case STA_NULLFUNC: sta->timeout_next = STA_DISASSOC; eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer, hapd, sta); break; case STA_DISASSOC: sta->flags &= ~WLAN_STA_ASSOC; ieee802_1x_set_port_enabled(hapd, sta, 0); if (!sta->acct_terminate_cause) sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated due to " "inactivity"); sta->timeout_next = STA_DEAUTH; eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, hapd, sta); break; case STA_DEAUTH: case STA_REMOVE: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " "inactivity"); if (!sta->acct_terminate_cause) sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT; ap_free_sta(hapd, sta); break; } }
static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype) { struct ieee80211_hdr *hdr; u16 fc, ethertype; u8 *pos, *sa; size_t left; struct sta_info *sta; if (len < sizeof(struct ieee80211_hdr)) return; hdr = (struct ieee80211_hdr *) buf; fc = le_to_host16(hdr->frame_control); if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) { printf("Not ToDS data frame (fc=0x%04x)\n", fc); return; } sa = hdr->addr2; sta = ap_get_sta(hapd, sa); if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { printf("Data frame from not associated STA " MACSTR "\n", MAC2STR(sa)); if (sta && (sta->flags & WLAN_STA_AUTH)) hostapd_sta_disassoc( hapd, sa, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); else hostapd_sta_deauth( hapd, sa, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); return; } pos = (u8 *) (hdr + 1); left = len - sizeof(*hdr); if (left < sizeof(rfc1042_header)) { printf("Too short data frame\n"); return; } if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) { printf("Data frame with no RFC1042 header\n"); return; } pos += sizeof(rfc1042_header); left -= sizeof(rfc1042_header); if (left < 2) { printf("No ethertype in data frame\n"); return; } ethertype = WPA_GET_BE16(pos); pos += 2; left -= 2; switch (ethertype) { case ETH_P_PAE: ieee802_1x_receive(hapd, sa, pos, left); break; default: printf("Unknown ethertype 0x%04x in data frame\n", ethertype); break; } }