/* This function will be called whenever a station associates with the AP */ void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta, int reassoc) { 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 and WPA are not used. * IEEE 802.1X/WPA code will start accounting after the station has * been authorized. */ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) accounting_sta_start(hapd, sta); /* Start IEEE 802.1X authentication process for new stations */ ieee802_1x_new_station(hapd, sta); if (reassoc) wpa_sm_event(hapd, sta, WPA_REAUTH); else wpa_new_station(hapd, sta); }
static u16 auth_shared_key(hostapd *hapd, struct sta_info *sta, u16 auth_transaction, u8 *challenge, int iswep) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication (shared key, transaction %d)", auth_transaction); if (auth_transaction == 1) { if (!sta->challenge) { /* Generate a pseudo-random challenge */ u8 key[8]; time_t now; int r; sta->challenge = malloc(WLAN_AUTH_CHALLENGE_LEN); if (!sta->challenge) return WLAN_STATUS_UNSPECIFIED_FAILURE; memset(sta->challenge, 0, WLAN_AUTH_CHALLENGE_LEN); now = time(NULL); r = random(); memcpy(key, &now, 4); memcpy(key + 4, &r, 4); rc4(sta->challenge, WLAN_AUTH_CHALLENGE_LEN, key, sizeof(key)); } return 0; } if (auth_transaction != 3) return WLAN_STATUS_UNSPECIFIED_FAILURE; /* Transaction 3 */ if (!iswep || !sta->challenge || !challenge || memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "shared key authentication - invalid " "challenge-response"); return WLAN_STATUS_CHALLENGE_FAIL; } hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (shared key)"); #ifdef IEEE80211_REQUIRE_AUTH_ACK /* Station will be marked authenticated if it ACKs the * authentication reply. */ #else sta->flags |= WLAN_STA_AUTH; wpa_sm_event(hapd, sta, WPA_AUTH); #endif free(sta->challenge); sta->challenge = NULL; return 0; }
static void handle_disassoc(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) { printf("handle_disassoc - too short payload (len=%lu)\n", (unsigned long) len); return; } HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "disassocation: STA=" MACSTR " reason_code=%d\n", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code)); if (hapd->assoc_ap_state != DO_NOT_ASSOC && memcmp(mgmt->sa, hapd->conf->assoc_ap_addr, ETH_ALEN) == 0) { printf("Assoc AP " MACSTR " sent disassociation " "(reason_code=%d) - try to authenticate\n", MAC2STR(hapd->conf->assoc_ap_addr), le_to_host16(mgmt->u.disassoc.reason_code)); hapd->assoc_ap_state = AUTHENTICATE; ieee802_11_sta_authenticate(hapd, NULL); eloop_register_timeout(0, 500000, ieee802_11_sta_authenticate, hapd, NULL); return; } sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { printf("Station " MACSTR " trying to disassociate, but it " "is not associated.\n", MAC2STR(mgmt->sa)); return; } sta->flags &= ~WLAN_STA_ASSOC; wpa_sm_event(hapd, sta, WPA_DISASSOC); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "disassociated"); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_set_port_enabled(hapd, sta, 0); /* Stop Accounting and IEEE 802.1X sessions, but leave the STA * authenticated. */ accounting_sta_stop(hapd, sta); ieee802_1x_free_station(sta); hostapd_sta_remove(hapd, sta->addr); if (sta->timeout_next == STA_NULLFUNC || sta->timeout_next == STA_DISASSOC) { sta->timeout_next = STA_DEAUTH; eloop_cancel_timeout(ap_handle_timer, hapd, sta); eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer, hapd, sta); } }
static void handle_deauth(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) { printf("handle_deauth - too short payload (len=%lu)\n", (unsigned long) len); return; } HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "deauthentication: STA=" MACSTR " reason_code=%d\n", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); if (hapd->assoc_ap_state != DO_NOT_ASSOC && memcmp(mgmt->sa, hapd->conf->assoc_ap_addr, ETH_ALEN) == 0) { printf("Assoc AP " MACSTR " sent deauthentication " "(reason_code=%d) - try to authenticate\n", MAC2STR(hapd->conf->assoc_ap_addr), le_to_host16(mgmt->u.deauth.reason_code)); hapd->assoc_ap_state = AUTHENTICATE; eloop_register_timeout(0, 500000, ieee802_11_sta_authenticate, hapd, NULL); return; } sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { printf("Station " MACSTR " trying to deauthenticate, but it " "is not authenticated.\n", MAC2STR(mgmt->sa)); return; } sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC); wpa_sm_event(hapd, sta, WPA_DEAUTH); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "deauthenticated"); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_set_port_enabled(hapd, sta, 0); ap_free_sta(hapd, sta); }
static int bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct hostapd_config *conf = hapd->conf; struct sta_info *sta; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deassociated"); sta = ap_get_sta(hapd, addr); if (sta != NULL) { sta->flags &= ~WLAN_STA_ASSOC; if (conf->wpa) wpa_sm_event(hapd, sta, WPA_DISASSOC); sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST; ieee802_1x_set_port_enabled(hapd, sta, 0); ap_free_sta(hapd, sta); } return 0; }
static int bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN]) { struct hostapd_data *hapd = drv->hapd; struct hostapd_config *conf = hapd->conf; struct sta_info *sta; struct ieee80211req_wpaie ie; int new_assoc, ielen, res; hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated"); sta = ap_sta_add(hapd, addr); if (sta == NULL) return -1; /* * Fetch and validate any negotiated WPA/RSN parameters. */ if (conf->wpa) { memset(&ie, 0, sizeof(ie)); memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN); if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) { printf("Failed to get WPA/RSN information element.\n"); return -1; /* XXX not right */ } ielen = ie.wpa_ie[1]; if (ielen == 0) { printf("No WPA/RSN information element for station!\n"); return -1; /* XXX not right */ } ielen += 2; res = wpa_validate_wpa_ie(hapd, sta, ie.wpa_ie, ielen, ie.wpa_ie[0] == WLAN_EID_RSN ? HOSTAPD_WPA_VERSION_WPA2 : HOSTAPD_WPA_VERSION_WPA); if (res != WPA_IE_OK) { printf("WPA/RSN information element rejected? " "(res %u)\n", res); return -1; } if (sta->wpa_ie != NULL) free(sta->wpa_ie); sta->wpa_ie = malloc(ielen); if (sta->wpa_ie == NULL) { printf("No memory for WPA/RSN information element!\n"); return -1; } memcpy(sta->wpa_ie, ie.wpa_ie, ielen); sta->wpa_ie_len = ielen; } else { if (sta->wpa_ie != NULL) free(sta->wpa_ie); sta->wpa_ie = NULL; sta->wpa_ie_len = 0; } /* * Now that the internal station state is setup * kick the authenticator into action. */ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0; sta->flags |= WLAN_STA_ASSOC; if (conf->wpa) wpa_sm_event(hapd, sta, WPA_ASSOC); if (new_assoc) hostapd_new_assoc_sta(hapd, sta); else if (conf->wpa) wpa_sm_event(hapd, sta, WPA_REAUTH); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); return 0; }
static void handle_auth(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len) { u16 auth_alg, auth_transaction, status_code; u16 resp = WLAN_STATUS_SUCCESS; struct sta_info *sta = NULL; int res; u16 fc; u8 *challenge = NULL; u32 session_timeout, acct_interim_interval; if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) { printf("handle_auth - too short payload (len=%lu)\n", (unsigned long) len); return; } auth_alg = le_to_host16(mgmt->u.auth.auth_alg); auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction); status_code = le_to_host16(mgmt->u.auth.status_code); fc = le_to_host16(mgmt->frame_control); if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) + 2 + WLAN_AUTH_CHALLENGE_LEN && mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE && mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN) challenge = &mgmt->u.auth.variable[2]; HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "authentication: STA=" MACSTR " auth_alg=%d " "auth_transaction=%d status_code=%d wep=%d%s\n", MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code, !!(fc & WLAN_FC_ISWEP), challenge ? " challenge" : ""); if (hapd->assoc_ap_state == AUTHENTICATE && auth_transaction == 2 && memcmp(mgmt->sa, hapd->conf->assoc_ap_addr, ETH_ALEN) == 0 && memcmp(mgmt->bssid, hapd->conf->assoc_ap_addr, ETH_ALEN) == 0) { if (status_code != 0) { printf("Authentication (as station) with AP " MACSTR " failed (status_code=%d)\n", MAC2STR(hapd->conf->assoc_ap_addr), status_code); return; } printf("Authenticated (as station) with AP " MACSTR "\n", MAC2STR(hapd->conf->assoc_ap_addr)); ieee802_11_sta_associate(hapd, NULL); return; } if (hapd->tkip_countermeasures) { resp = WLAN_REASON_MICHAEL_MIC_FAILURE; goto fail; } if (!(((hapd->conf->auth_algs & HOSTAPD_AUTH_OPEN) && auth_alg == WLAN_AUTH_OPEN) || ((hapd->conf->auth_algs & HOSTAPD_AUTH_SHARED_KEY) && auth_alg == WLAN_AUTH_SHARED_KEY))) { printf("Unsupported authentication algorithm (%d)\n", auth_alg); resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; goto fail; } if (!(auth_transaction == 1 || (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) { printf("Unknown authentication transaction number (%d)\n", auth_transaction); resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION; goto fail; } if (memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len, &session_timeout, &acct_interim_interval); if (res == HOSTAPD_ACL_REJECT) { printf("Station " MACSTR " not allowed to authenticate.\n", MAC2STR(mgmt->sa)); resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } if (res == HOSTAPD_ACL_PENDING) { HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Authentication frame " "from " MACSTR " waiting for an external " "authentication\n", MAC2STR(mgmt->sa)); /* Authentication code will re-send the authentication frame * after it has received (and cached) information from the * external source. */ return; } sta = ap_sta_add(hapd, mgmt->sa); if (!sta) { resp = WLAN_STATUS_UNSPECIFIED_FAILURE; goto fail; } sta->flags &= ~WLAN_STA_PREAUTH; ieee802_1x_notify_pre_auth(sta->eapol_sm, 0); if (hapd->conf->radius->acct_interim_interval == 0 && acct_interim_interval) sta->acct_interim_interval = acct_interim_interval; if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT) ap_sta_session_timeout(hapd, sta, session_timeout); else ap_sta_no_session_timeout(hapd, sta); switch (auth_alg) { case WLAN_AUTH_OPEN: hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "authentication OK (open system)"); #ifdef IEEE80211_REQUIRE_AUTH_ACK /* Station will be marked authenticated if it ACKs the * authentication reply. */ #else sta->flags |= WLAN_STA_AUTH; wpa_sm_event(hapd, sta, WPA_AUTH); #endif break; case WLAN_AUTH_SHARED_KEY: resp = auth_shared_key(hapd, sta, auth_transaction, challenge, fc & WLAN_FC_ISWEP); break; } fail: send_auth_reply(hapd, mgmt, auth_alg, auth_transaction + 1, resp, sta ? sta->challenge : NULL); }
static void handle_assoc_cb(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int ok) { u16 status; struct sta_info *sta; int new_assoc = 1; if (!ok) { hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "did not acknowledge association response"); return; } if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : sizeof(mgmt->u.assoc_req))) { printf("handle_assoc_cb(reassoc=%d) - too short payload " "(len=%lu)\n", reassoc, (unsigned long) len); return; } if (reassoc) status = le_to_host16(mgmt->u.reassoc_resp.status_code); else status = le_to_host16(mgmt->u.assoc_resp.status_code); sta = ap_get_sta(hapd, mgmt->da); if (!sta) { printf("handle_assoc_cb: STA " MACSTR " not found\n", MAC2STR(mgmt->da)); return; } if (status != WLAN_STATUS_SUCCESS) goto fail; /* Stop previous accounting session, if one is started, and allocate * new session id for the new session. */ accounting_sta_stop(hapd, sta); accounting_sta_get_id(hapd, sta); hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated (aid %d, accounting session %08X-%08X)", sta->aid, sta->acct_session_id_hi, sta->acct_session_id_lo); if (sta->flags & WLAN_STA_ASSOC) new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability, sta->tx_supp_rates)) { printf("Could not add station to kernel driver.\n"); } wpa_sm_event(hapd, sta, WPA_ASSOC); hostapd_new_assoc_sta(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); fail: /* Copy of the association request is not needed anymore */ if (sta->last_assoc_req) { free(sta->last_assoc_req); sta->last_assoc_req = NULL; } }
static void handle_assoc_cb(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len, int reassoc, int ok) { u16 status; struct prism2_hostapd_param param; struct sta_info *sta; int new_assoc = 1; if (!ok) { hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "did not acknowledge association response"); return; } if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) : sizeof(mgmt->u.assoc_req))) { printf("handle_assoc_cb(reassoc=%d) - too short payload " "(len=%d)\n", reassoc, len); return; } if (reassoc) status = le_to_host16(mgmt->u.reassoc_resp.status_code); else status = le_to_host16(mgmt->u.assoc_resp.status_code); sta = ap_get_sta(hapd, mgmt->da); if (!sta) { printf("handle_assoc_cb: STA " MACSTR " not found\n", MAC2STR(mgmt->da)); return; } if (status != WLAN_STATUS_SUCCESS) goto fail; hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "associated (aid %d)", sta->aid); if (sta->flags & WLAN_STA_ASSOC) new_assoc = 0; sta->flags |= WLAN_STA_ASSOC; memset(¶m, 0, sizeof(param)); param.cmd = PRISM2_HOSTAPD_ADD_STA; memcpy(param.sta_addr, sta->addr, ETH_ALEN); param.u.add_sta.aid = sta->aid; param.u.add_sta.capability = sta->capability; param.u.add_sta.tx_supp_rates = sta->tx_supp_rates; if (hostapd_ioctl(hapd->driver.data, ¶m, sizeof(param))) { printf("Could not add station to kernel driver.\n"); } wpa_sm_event(hapd, sta, WPA_ASSOC); if (new_assoc) hostapd_new_assoc_sta(hapd, sta); else wpa_sm_event(hapd, sta, WPA_REAUTH); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); fail: /* Copy of the association request is not needed anymore */ if (sta->last_assoc_req) { free(sta->last_assoc_req); sta->last_assoc_req = NULL; } }