X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=hostapd%2Fieee802_11.c;h=79688502bcbd4342f2ef80e87ffbf1131dd940d4;hb=fda90ab4b73b19d4638e8b7cd4c90458e51f9e3e;hp=aa493fea0ab372d6a746ed83a846dcf13a4edf89;hpb=a8d8410e1fc0d88de314a960d7c5c70a76cae883;p=wpasupplicant diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c index aa493fe..7968850 100644 --- a/hostapd/ieee802_11.c +++ b/hostapd/ieee802_11.c @@ -34,7 +34,7 @@ #include "wme.h" #include "ap_list.h" #include "accounting.h" -#include "driver.h" +#include "driver_i.h" #include "mlme.h" @@ -150,9 +150,11 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid) oper->control_chan = hapd->iconf->channel; oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode); if (hapd->iconf->secondary_channel == 1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE | + HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; if (hapd->iconf->secondary_channel == -1) - oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; + oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW | + HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH; pos += sizeof(*oper); @@ -296,12 +298,21 @@ static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd, struct sta_info *sta, u8 *eid) { u8 *pos = eid; - u32 timeout; - - *pos++ = WLAN_EID_ASSOC_COMEBACK_TIME; - *pos++ = 4; - timeout = (hapd->conf->assoc_ping_attempts - sta->ping_count + 1) * - hapd->conf->assoc_ping_timeout; + u32 timeout, tu; + struct os_time now, passed; + + *pos++ = WLAN_EID_TIMEOUT_INTERVAL; + *pos++ = 5; + *pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK; + os_get_time(&now); + os_time_sub(&now, &sta->sa_query_start, &passed); + tu = (passed.sec * 1000000 + passed.usec) / 1024; + if (hapd->conf->assoc_sa_query_max_timeout > tu) + timeout = hapd->conf->assoc_sa_query_max_timeout - tu; + else + timeout = 0; + if (timeout < hapd->conf->assoc_sa_query_max_timeout) + timeout++; /* add some extra time for local timers */ WPA_PUT_LE32(pos, timeout); pos += 4; @@ -325,6 +336,12 @@ void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len) } +/** + * ieee802_11_send_deauth - Send Deauthentication frame + * @hapd: hostapd BSS data + * @addr: Address of the destination STA + * @reason: Reason code for Deauthentication + */ void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason) { struct ieee80211_mgmt mgmt; @@ -805,9 +822,8 @@ static void handle_assoc(struct hostapd_data *hapd, /* save HT capabilities in the sta object */ os_memset(&sta->ht_capabilities, 0, sizeof(sta->ht_capabilities)); if (elems.ht_capabilities && - elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_capability) - && (sta->flags & WLAN_STA_WME)) { - /* note: without WMM capability, treat the sta as non-HT */ + elems.ht_capabilities_len >= + sizeof(struct ieee80211_ht_capability)) { sta->flags |= WLAN_STA_HT; sta->ht_capabilities.id = WLAN_EID_HT_CAP; sta->ht_capabilities.length = @@ -831,12 +847,16 @@ static void handle_assoc(struct hostapd_data *hapd, wpa_ie_len = 0; } #ifdef CONFIG_WPS + sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS); if (hapd->conf->wps_state && wpa_ie == NULL) { if (elems.wps_ie) { wpa_printf(MSG_DEBUG, "STA included WPS IE in " "(Re)Association Request - assume WPS is " "used"); sta->flags |= WLAN_STA_WPS; + wpabuf_free(sta->wps_ie); + sta->wps_ie = wpabuf_alloc_copy(elems.wps_ie + 4, + elems.wps_ie_len - 4); } else { wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE " "in (Re)Association Request - possible WPS " @@ -877,9 +897,9 @@ static void handle_assoc(struct hostapd_data *hapd, resp = WLAN_STATUS_UNSPECIFIED_FAILURE; #ifdef CONFIG_IEEE80211W else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; /* FIX */ + resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) - resp = WLAN_STATUS_UNSPECIFIED_FAILURE; /* FIX */ + resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; #endif /* CONFIG_IEEE80211W */ else if (res == WPA_INVALID_MDIE) resp = WLAN_STATUS_INVALID_MDIE; @@ -888,16 +908,20 @@ static void handle_assoc(struct hostapd_data *hapd, if (resp != WLAN_STATUS_SUCCESS) goto fail; #ifdef CONFIG_IEEE80211W - if ((sta->flags & WLAN_STA_MFP) && !sta->ping_timed_out) { + if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + sta->sa_query_count > 0) + ap_check_sa_query_timeout(hapd, sta); + if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out && + (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) { /* - * STA has already been associated with MFP and ping - * timeout has not been reached. Reject the - * association attempt temporarily and start ping, if - * one is not pending. + * STA has already been associated with MFP and SA + * Query timeout has not been reached. Reject the + * association attempt temporarily and start SA Query, + * if one is not pending. */ - if (sta->ping_count == 0) - ap_sta_start_ping(hapd, sta); + if (sta->sa_query_count == 0) + ap_sta_start_sa_query(hapd, sta); resp = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY; goto fail; @@ -925,7 +949,18 @@ static void handle_assoc(struct hostapd_data *hapd, goto fail; } #endif /* CONFIG_IEEE80211R */ - } +#ifdef CONFIG_IEEE80211N + if ((sta->flags & WLAN_STA_HT) && + wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) { + wpa_printf(MSG_DEBUG, "HT: " MACSTR " tried to " + "use TKIP with HT association", + MAC2STR(sta->addr)); + resp = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; + goto fail; + } +#endif /* CONFIG_IEEE80211N */ + } else + wpa_auth_sta_no_wpa(sta->wpa_sm); if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) sta->flags |= WLAN_STA_NONERP; @@ -973,21 +1008,30 @@ static void handle_assoc(struct hostapd_data *hapd, wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities " "Info: 0x%04x", MAC2STR(sta->addr), ht_capab); if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) { - hapd->iface->num_sta_ht_no_gf++; + if (!sta->no_ht_gf_set) { + sta->no_ht_gf_set = 1; + hapd->iface->num_sta_ht_no_gf++; + } wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no " "greenfield, num of non-gf stations %d", __func__, MAC2STR(sta->addr), hapd->iface->num_sta_ht_no_gf); } if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) { - hapd->iface->num_sta_ht_20mhz++; + if (!sta->ht_20mhz_set) { + sta->ht_20mhz_set = 1; + hapd->iface->num_sta_ht_20mhz++; + } wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, " "num of 20MHz HT STAs %d", __func__, MAC2STR(sta->addr), hapd->iface->num_sta_ht_20mhz); } } else { - hapd->iface->num_sta_no_ht++; + if (!sta->no_ht_set) { + sta->no_ht_set = 1; + hapd->iface->num_sta_no_ht++; + } if (hapd->iconf->ieee80211n) { wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of non-HT stations %d", @@ -1024,6 +1068,19 @@ static void handle_assoc(struct hostapd_data *hapd, /* Station will be marked associated, after it acknowledges AssocResp */ +#ifdef CONFIG_IEEE80211W + if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) { + wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out " + "SA Query procedure", reassoc ? "re" : ""); + /* TODO: Send a protected Disassociate frame to the STA using + * the old key and Reason Code "Previous Authentication no + * longer valid". Make sure this is only sent protected since + * unprotected frame would be received by the STA that is now + * trying to associate. + */ + } +#endif /* CONFIG_IEEE80211W */ + if (reassoc) { os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap, ETH_ALEN); @@ -1200,51 +1257,78 @@ static void handle_beacon(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211W -static void hostapd_ping_action(struct hostapd_data *hapd, - struct ieee80211_mgmt *mgmt, size_t len) + +/* MLME-SAQuery.request */ +void ieee802_11_send_sa_query_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_SA_QUERY; + mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST; + os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id, + WLAN_SA_QUERY_TR_ID_LEN); + end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN; + if (hostapd_send_mgmt_frame(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0) + perror("ieee802_11_send_sa_query_req: send"); +} + + +static void hostapd_sa_query_action(struct hostapd_data *hapd, + struct ieee80211_mgmt *mgmt, size_t len) { struct sta_info *sta; u8 *end; int i; - end = mgmt->u.action.u.ping_resp.trans_id + WLAN_PING_TRANS_ID_LEN; + end = mgmt->u.action.u.sa_query_resp.trans_id + + WLAN_SA_QUERY_TR_ID_LEN; if (((u8 *) mgmt) + len < end) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short Ping Action " + wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action " "frame (len=%lu)", (unsigned long) len); return; } - if (mgmt->u.action.u.ping_resp.action != WLAN_PING_RESPONSE) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected Ping Action %d", - mgmt->u.action.u.ping_resp.action); + if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query " + "Action %d", mgmt->u.action.u.sa_query_resp.action); return; } - /* MLME-PING.confirm */ + /* MLME-SAQuery.confirm */ sta = ap_get_sta(hapd, mgmt->sa); - if (sta == NULL || sta->ping_trans_id == NULL) { + if (sta == NULL || sta->sa_query_trans_id == NULL) { wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with " - "pending ping request found"); + "pending SA Query request found"); return; } - for (i = 0; i < sta->ping_count; i++) { - if (os_memcmp(sta->ping_trans_id + i * WLAN_PING_TRANS_ID_LEN, - mgmt->u.action.u.ping_resp.trans_id, - WLAN_PING_TRANS_ID_LEN) == 0) + for (i = 0; i < sta->sa_query_count; i++) { + if (os_memcmp(sta->sa_query_trans_id + + i * WLAN_SA_QUERY_TR_ID_LEN, + mgmt->u.action.u.sa_query_resp.trans_id, + WLAN_SA_QUERY_TR_ID_LEN) == 0) break; } - if (i >= sta->ping_count) { - wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching ping " + if (i >= sta->sa_query_count) { + wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query " "transaction identifier found"); return; } hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_DEBUG, "Reply to pending ping received"); - ap_sta_stop_ping(hapd, sta); + HOSTAPD_LEVEL_DEBUG, + "Reply to pending SA Query received"); + ap_sta_stop_sa_query(hapd, sta); } #endif /* CONFIG_IEEE80211W */ @@ -1285,8 +1369,8 @@ static void handle_action(struct hostapd_data *hapd, hostapd_wme_action(hapd, mgmt, len); return; #ifdef CONFIG_IEEE80211W - case WLAN_ACTION_PING: - hostapd_ping_action(hapd, mgmt, len); + case WLAN_ACTION_SA_QUERY: + hostapd_sa_query_action(hapd, mgmt, len); return; #endif /* CONFIG_IEEE80211W */ } @@ -1322,6 +1406,7 @@ static void handle_action(struct hostapd_data *hapd, * @buf: management frame data (starting from IEEE 802.11 header) * @len: length of frame data in octets * @stype: management frame subtype from frame control field + * @fi: meta data about received frame (signal level, etc.) * * Process all incoming IEEE 802.11 management frames. This will be called for * each frame received from the kernel driver through wlan#ap interface. In @@ -1504,7 +1589,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, #endif /* CONFIG_IEEE80211N */ #ifdef CONFIG_IEEE80211W - sta->ping_timed_out = 0; + sta->sa_query_timed_out = 0; #endif /* CONFIG_IEEE80211W */ if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid, @@ -1553,6 +1638,15 @@ static void handle_assoc_cb(struct hostapd_data *hapd, } +/** + * ieee802_11_mgmt_cb - Process management frame TX status callback + * @hapd: hostapd BSS data structure (the BSS from which the management frame + * was sent from) + * @buf: management frame data (starting from IEEE 802.11 header) + * @len: length of frame data in octets + * @stype: management frame subtype from frame control field + * @ok: Whether the frame was ACK'ed + */ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype, int ok) { @@ -1587,76 +1681,6 @@ void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len, } -static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx, - void *timeout_ctx) -{ - struct hostapd_data *hapd = eloop_ctx; - hapd->tkip_countermeasures = 0; - hostapd_set_countermeasures(hapd, 0); - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended"); -} - - -static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd) -{ - struct sta_info *sta; - - hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated"); - - wpa_auth_countermeasures_start(hapd->wpa_auth); - hapd->tkip_countermeasures = 1; - hostapd_set_countermeasures(hapd, 1); - wpa_gtk_rekey(hapd->wpa_auth); - eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL); - eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop, - hapd, NULL); - for (sta = hapd->sta_list; sta != NULL; sta = sta->next) { - hostapd_sta_deauth(hapd, sta->addr, - WLAN_REASON_MICHAEL_MIC_FAILURE); - sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | - WLAN_STA_AUTHORIZED); - hostapd_sta_remove(hapd, sta->addr); - } -} - - -void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, - int local) -{ - time_t now; - - if (addr && local) { - struct sta_info *sta = ap_get_sta(hapd, addr); - if (sta != NULL) { - wpa_auth_sta_local_mic_failure_report(sta->wpa_sm); - hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211, - HOSTAPD_LEVEL_INFO, - "Michael MIC failure detected in " - "received frame"); - mlme_michaelmicfailure_indication(hapd, addr); - } else { - wpa_printf(MSG_DEBUG, - "MLME-MICHAELMICFAILURE.indication " - "for not associated STA (" MACSTR - ") ignored", MAC2STR(addr)); - return; - } - } - - time(&now); - if (now > hapd->michael_mic_failure + 60) { - hapd->michael_mic_failures = 1; - } else { - hapd->michael_mic_failures++; - if (hapd->michael_mic_failures > 1) - ieee80211_tkip_countermeasures_start(hapd); - } - hapd->michael_mic_failure = now; -} - - int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen) { /* TODO */