示例#1
0
struct radius_client_data *
radius_client_reconfig(struct radius_client_data *old, void *ctx,
		       struct hostapd_radius_servers *oldconf,
		       struct hostapd_radius_servers *newconf)
{
	radius_client_flush(old, 0);

	if (newconf->retry_primary_interval !=
	    oldconf->retry_primary_interval ||
	    newconf->num_auth_servers != oldconf->num_auth_servers ||
	    newconf->num_acct_servers != oldconf->num_acct_servers ||
	    radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
				newconf->num_auth_servers) ||
	    radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
				newconf->num_acct_servers)) {
		hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_DEBUG,
			       "Reconfiguring RADIUS client");
		radius_client_deinit(old);
		return radius_client_init(ctx, newconf);
	}

	return old;
}
示例#2
0
/**
 * hostapd_select_hw_mode - Select the hardware mode
 * @iface: Pointer to interface data.
 * Returns: 0 on success, -1 on failure
 *
 * Sets up the hardware mode, channel, rates, and passive scanning
 * based on the configuration.
 */
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
	int i, j, ok;

	if (iface->num_hw_features < 1)
		return -1;

	iface->current_mode = NULL;
	for (i = 0; i < iface->num_hw_features; i++) {
		struct hostapd_hw_modes *mode = &iface->hw_features[i];
		if (mode->mode == iface->conf->hw_mode) {
			iface->current_mode = mode;
			break;
		}
	}

	if (iface->current_mode == NULL) {
		wpa_printf(MSG_ERROR, "Hardware does not support configured "
			   "mode");
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured mode "
			       "(%d)", (int) iface->conf->hw_mode);
		return -1;
	}

	ok = 0;
	for (j = 0; j < iface->current_mode->num_channels; j++) {
		struct hostapd_channel_data *chan =
			&iface->current_mode->channels[j];
		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
		    (chan->chan == iface->conf->channel)) {
			ok = 1;
			break;
		}
	}
	if (iface->conf->channel == 0) {
		/* TODO: could request a scan of neighboring BSSes and select
		 * the channel automatically */
		wpa_printf(MSG_ERROR, "Channel not configured "
			   "(hw_mode/channel in hostapd.conf)");
		return -1;
	}
	if (ok == 0 && iface->conf->channel != 0) {
		hostapd_logger(iface->bss[0], NULL,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Configured channel (%d) not found from the "
			       "channel list of current mode (%d) %s",
			       iface->conf->channel,
			       iface->current_mode->mode,
			       hostapd_hw_mode_txt(iface->current_mode->mode));
		iface->current_mode = NULL;
	}

	if (iface->current_mode == NULL) {
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured channel");
		return -1;
	}

	if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
		wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
					   HOSTAPD_LEVEL_WARNING,
					   "Failed to prepare rates table.");
		return -1;
	}

	return 0;
}
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
			const u8 *req_ies, size_t req_ies_len, int reassoc)
{
	struct sta_info *sta;
	int new_assoc, res;
	struct ieee802_11_elems elems;
	const u8 *ie;
	size_t ielen;
#ifdef CONFIG_IEEE80211R
	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
	u8 *p = buf;
#endif /* CONFIG_IEEE80211R */
	u16 reason = WLAN_REASON_UNSPECIFIED;
	u16 status = WLAN_STATUS_SUCCESS;
	const u8 *p2p_dev_addr = NULL;

	if (addr == NULL) {
		/*
		 * This could potentially happen with unexpected event from the
		 * driver wrapper. This was seen at least in one case where the
		 * driver ended up being set to station mode while hostapd was
		 * running, so better make sure we stop processing such an
		 * event here.
		 */
		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
			   "no address");
		return -1;
	}
	random_add_randomness(addr, ETH_ALEN);

	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_INFO, "associated");

	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
	if (elems.wps_ie) {
		ie = elems.wps_ie - 2;
		ielen = elems.wps_ie_len + 2;
		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
	} else if (elems.rsn_ie) {
		ie = elems.rsn_ie - 2;
		ielen = elems.rsn_ie_len + 2;
		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
	} else if (elems.wpa_ie) {
		ie = elems.wpa_ie - 2;
		ielen = elems.wpa_ie_len + 2;
		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
#ifdef CONFIG_HS20
	} else if (elems.osen) {
		ie = elems.osen - 2;
		ielen = elems.osen_len + 2;
		wpa_printf(MSG_DEBUG, "STA included OSEN IE in (Re)AssocReq");
#endif /* CONFIG_HS20 */
	} else {
		ie = NULL;
		ielen = 0;
		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
			   "(Re)AssocReq");
	}

	sta = ap_get_sta(hapd, addr);
	if (sta) {
		ap_sta_no_session_timeout(hapd, sta);
		accounting_sta_stop(hapd, sta);

		/*
		 * Make sure that the previously registered inactivity timer
		 * will not remove the STA immediately.
		 */
		sta->timeout_next = STA_NULLFUNC;
	} else {
		sta = ap_sta_add(hapd, addr);
		if (sta == NULL) {
			hostapd_drv_sta_disassoc(hapd, addr,
						 WLAN_REASON_DISASSOC_AP_BUSY);
			return -1;
		}
	}
	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);

#ifdef CONFIG_P2P
	if (elems.p2p) {
		wpabuf_free(sta->p2p_ie);
		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
							  P2P_IE_VENDOR_TYPE);
		if (sta->p2p_ie)
			p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
	}
#endif /* CONFIG_P2P */

#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
	if (elems.ht_capabilities &&
	    elems.ht_capabilities_len >=
	    sizeof(struct ieee80211_ht_capabilities) &&
	    (hapd->iface->conf->ht_capab &
	     HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
		struct ieee80211_ht_capabilities *ht_cap =
			(struct ieee80211_ht_capabilities *)
			elems.ht_capabilities;

		if (le_to_host16(ht_cap->ht_capabilities_info) &
		    HT_CAP_INFO_40MHZ_INTOLERANT)
			ht40_intolerant_add(hapd->iface, sta);
	}
#endif /* NEED_AP_MLME */
#endif /* CONFIG_IEEE80211N */

#ifdef CONFIG_INTERWORKING
	if (elems.ext_capab && elems.ext_capab_len > 4) {
		if (elems.ext_capab[4] & 0x01)
			sta->qos_map_enabled = 1;
	}
#endif /* CONFIG_INTERWORKING */

#ifdef CONFIG_HS20
	wpabuf_free(sta->hs20_ie);
	if (elems.hs20 && elems.hs20_len > 4) {
		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
						 elems.hs20_len - 4);
	} else
		sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_MTK_P2P
		if (elems.wfd && (elems.wfd_len > 0)) {
			struct p2p_message msg;
			wpabuf_free(sta->wfd_ie);
			sta->wfd_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
								  WFD_IE_VENDOR_TYPE);
			if(p2p_parse_wfd_ie(sta->wfd_ie,&msg)==0) {
				wpa_printf(MSG_DEBUG, "Change our WFD role and peer wfd_ie");
				if(hapd->p2p) {
					wpa_printf(MSG_DEBUG, "Change our WFD role and peer wfd_ie 2");
					wfd_process_request_and_switch_role(hapd->p2p, &msg, 0);
				}
			}
		}
#endif /* CONFIG_MTK_P2P */
	if (hapd->conf->wpa) {
		if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
			if (hapd->conf->wps_state) {
				wpa_printf(MSG_DEBUG, "STA did not include "
					   "WPA/RSN IE in (Re)Association "
					   "Request - possible WPS use");
				sta->flags |= WLAN_STA_MAYBE_WPS;
				goto skip_wpa_check;
			}
#endif /* CONFIG_WPS */

			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
			return -1;
		}
#ifdef CONFIG_WPS
		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
			struct wpabuf *wps;
			sta->flags |= WLAN_STA_WPS;
			wps = ieee802_11_vendor_ie_concat(ie, ielen,
							  WPS_IE_VENDOR_TYPE);
			if (wps) {
				if (wps_is_20(wps)) {
					wpa_printf(MSG_DEBUG, "WPS: STA "
						   "supports WPS 2.0");
					sta->flags |= WLAN_STA_WPS2;
				}
				wpabuf_free(wps);
			}
			goto skip_wpa_check;
		}
#endif /* CONFIG_WPS */

		if (sta->wpa_sm == NULL)
			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
							sta->addr,
							p2p_dev_addr);
		if (sta->wpa_sm == NULL) {
			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
				   "machine");
			return -1;
		}
		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
					  ie, ielen,
					  elems.mdie, elems.mdie_len);
		if (res != WPA_IE_OK) {
			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
				   "rejected? (res %u)", res);
			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
			if (res == WPA_INVALID_GROUP) {
				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
			} else if (res == WPA_INVALID_PAIRWISE) {
				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
			} else if (res == WPA_INVALID_AKMP) {
				reason = WLAN_REASON_AKMP_NOT_VALID;
				status = WLAN_STATUS_AKMP_NOT_VALID;
			}
#ifdef CONFIG_IEEE80211W
			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
				reason = WLAN_REASON_INVALID_IE;
				status = WLAN_STATUS_INVALID_IE;
			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
			}
#endif /* CONFIG_IEEE80211W */
			else {
				reason = WLAN_REASON_INVALID_IE;
				status = WLAN_STATUS_INVALID_IE;
			}
			goto fail;
		}
#ifdef CONFIG_IEEE80211W
		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 &&
		    (sta->auth_alg != WLAN_AUTH_FT)) {
			/*
			 * 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->sa_query_count == 0)
				ap_sta_start_sa_query(hapd, sta);

#ifdef CONFIG_IEEE80211R
			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;

			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);

			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
					  p - buf);
#endif /* CONFIG_IEEE80211R */
			return 0;
		}

		if (wpa_auth_uses_mfp(sta->wpa_sm))
			sta->flags |= WLAN_STA_MFP;
		else
			sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */

#ifdef CONFIG_IEEE80211R
		if (sta->auth_alg == WLAN_AUTH_FT) {
			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
							 req_ies_len);
			if (status != WLAN_STATUS_SUCCESS) {
				if (status == WLAN_STATUS_INVALID_PMKID)
					reason = WLAN_REASON_INVALID_IE;
				if (status == WLAN_STATUS_INVALID_MDIE)
					reason = WLAN_REASON_INVALID_IE;
				if (status == WLAN_STATUS_INVALID_FTIE)
					reason = WLAN_REASON_INVALID_IE;
				goto fail;
			}
		}
#endif /* CONFIG_IEEE80211R */
	} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
		struct wpabuf *wps;
		if (req_ies)
			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
							  WPS_IE_VENDOR_TYPE);
		else
			wps = NULL;
#ifdef CONFIG_WPS_STRICT
		if (wps && wps_validate_assoc_req(wps) < 0) {
			reason = WLAN_REASON_INVALID_IE;
			status = WLAN_STATUS_INVALID_IE;
			wpabuf_free(wps);
			goto fail;
		}
#endif /* CONFIG_WPS_STRICT */
		if (wps) {
			sta->flags |= WLAN_STA_WPS;
			if (wps_is_20(wps)) {
				wpa_printf(MSG_DEBUG, "WPS: STA supports "
					   "WPS 2.0");
				sta->flags |= WLAN_STA_WPS2;
			}
		} else
			sta->flags |= WLAN_STA_MAYBE_WPS;
		wpabuf_free(wps);
#endif /* CONFIG_WPS */
#ifdef CONFIG_HS20
	} else if (hapd->conf->osen) {
		if (elems.osen == NULL) {
			hostapd_logger(
				hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
				HOSTAPD_LEVEL_INFO,
				"No HS 2.0 OSEN element in association request");
			return WLAN_STATUS_INVALID_IE;
		}

		wpa_printf(MSG_DEBUG, "HS 2.0: OSEN association");
		if (sta->wpa_sm == NULL)
			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
							sta->addr, NULL);
		if (sta->wpa_sm == NULL) {
			wpa_printf(MSG_WARNING, "Failed to initialize WPA "
				   "state machine");
			return WLAN_STATUS_UNSPECIFIED_FAILURE;
		}
		if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
				      elems.osen - 2, elems.osen_len + 2) < 0)
			return WLAN_STATUS_INVALID_IE;
#endif /* CONFIG_HS20 */
	}
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */

#ifdef CONFIG_IEEE80211R
	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
					sta->auth_alg, req_ies, req_ies_len);

	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);

	if (sta->auth_alg == WLAN_AUTH_FT)
		ap_sta_set_authorized(hapd, sta, 1);
#else /* CONFIG_IEEE80211R */
	/* Keep compiler silent about unused variables */
	if (status) {
	}
#endif /* CONFIG_IEEE80211R */

	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
	sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE;

	hostapd_set_sta_flags(hapd, sta);

	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
	else
		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);

	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
/*
[ALPS00326459][6575JB][BSP Package][6577JB][CTS Verifier 4.1_r2][MT6577_PHONE][changelist 996001]
GROUP JOIN 2 cases fail in Wi-Fi Direct Test
*/
#if defined(CONFIG_MTK_P2P) || defined(CONFIG_HOTSPOT_MGR_SUPPORT)
	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
		sta->auth_alg == WLAN_AUTH_FT) {
		/*
		 * Open, static WEP, or FT protocol; no separate authorization
		 * step.
		 */
		wpa_msg(hapd->msg_ctx, MSG_INFO,
		AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
	}
#endif /* CONFIG_MTK_P2P || CONFIG_HOTSPOT_MGR_SUPPORT */

	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);

#ifdef CONFIG_P2P
	if (req_ies) {
		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
				      req_ies, req_ies_len);
	}
#endif /* CONFIG_P2P */

	return 0;

fail:
#ifdef CONFIG_IEEE80211R
	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R */
	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
	ap_free_sta(hapd, sta);
	return -1;
}
示例#4
0
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;
    }
}
示例#5
0
/**
 * radius_client_send - Send a RADIUS request
 * @radius: RADIUS client context from radius_client_init()
 * @msg: RADIUS message to be sent
 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
 * @addr: MAC address of the device related to this message or %NULL
 * Returns: 0 on success, -1 on failure
 *
 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
 * between accounting and interim accounting messages is that the interim
 * message will not be retransmitted. Instead, a callback is used to indicate
 * that the transmission failed for the specific station @addr so that a new
 * interim accounting update message can be generated with up-to-date session
 * data instead of trying to resend old information.
 *
 * The message is added on the retransmission queue and will be retransmitted
 * automatically until a response is received or maximum number of retries
 * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
 * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
 * automatically on transmission failure.
 *
 * The related device MAC address can be used to identify pending messages that
 * can be removed with radius_client_flush_auth().
 */
int radius_client_send(struct radius_client_data *radius,
		       struct radius_msg *msg, RadiusType msg_type,
		       const u8 *addr)
{
	struct hostapd_radius_servers *conf = radius->conf;
	const u8 *shared_secret;
	size_t shared_secret_len;
	char *name;
	int s, res;
	struct wpabuf *buf;

	if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
		if (conf->acct_server && radius->acct_sock < 0)
			radius_client_init_acct(radius);

		if (conf->acct_server == NULL || radius->acct_sock < 0 ||
		    conf->acct_server->shared_secret == NULL) {
			hostapd_logger(radius->ctx, NULL,
				       HOSTAPD_MODULE_RADIUS,
				       HOSTAPD_LEVEL_INFO,
				       "No accounting server configured");
			return -1;
		}
		shared_secret = conf->acct_server->shared_secret;
		shared_secret_len = conf->acct_server->shared_secret_len;
		radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
		name = "accounting";
		s = radius->acct_sock;
		conf->acct_server->requests++;
	} else {
		if (conf->auth_server && radius->auth_sock < 0)
			radius_client_init_auth(radius);

		if (conf->auth_server == NULL || radius->auth_sock < 0 ||
		    conf->auth_server->shared_secret == NULL) {
			hostapd_logger(radius->ctx, NULL,
				       HOSTAPD_MODULE_RADIUS,
				       HOSTAPD_LEVEL_INFO,
				       "No authentication server configured");
			return -1;
		}
		shared_secret = conf->auth_server->shared_secret;
		shared_secret_len = conf->auth_server->shared_secret_len;
		radius_msg_finish(msg, shared_secret, shared_secret_len);
		name = "authentication";
		s = radius->auth_sock;
		conf->auth_server->requests++;
	}

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
		       "server", name);
	if (conf->msg_dumps)
		radius_msg_dump(msg);

	buf = radius_msg_get_buf(msg);
	res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
	if (res < 0)
		radius_client_handle_send_error(radius, s, msg_type);

	radius_client_list_add(radius, msg, msg_type, shared_secret,
			       shared_secret_len, addr);

	return 0;
}
示例#6
0
static int radius_client_retransmit(struct radius_client_data *radius,
				    struct radius_msg_list *entry,
				    os_time_t now)
{
	struct hostapd_radius_servers *conf = radius->conf;
	int s;
	struct wpabuf *buf;
	size_t prev_num_msgs;
	u8 *acct_delay_time;
	size_t acct_delay_time_len;

	if (entry->msg_type == RADIUS_ACCT ||
	    entry->msg_type == RADIUS_ACCT_INTERIM) {
		if (radius->acct_sock < 0)
			radius_client_init_acct(radius);
		if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_acct_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->acct_sock;
		if (entry->attempts == 0)
			conf->acct_server->requests++;
		else {
			conf->acct_server->timeouts++;
			conf->acct_server->retransmissions++;
		}
	} else {
		if (radius->auth_sock < 0)
			radius_client_init_auth(radius);
		if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
			prev_num_msgs = radius->num_msgs;
			radius_client_auth_failover(radius);
			if (prev_num_msgs != radius->num_msgs)
				return 0;
		}
		s = radius->auth_sock;
		if (entry->attempts == 0)
			conf->auth_server->requests++;
		else {
			conf->auth_server->timeouts++;
			conf->auth_server->retransmissions++;
		}
	}

	if (entry->msg_type == RADIUS_ACCT_INTERIM) {
		wpa_printf(MSG_DEBUG,
			   "RADIUS: Failed to transmit interim accounting update to "
			   MACSTR " - drop message and request a new update",
			   MAC2STR(entry->addr));
		if (radius->interim_error_cb)
			radius->interim_error_cb(entry->addr,
						 radius->interim_error_cb_ctx);
		return 1;
	}

	if (s < 0) {
		wpa_printf(MSG_INFO,
			   "RADIUS: No valid socket for retransmission");
		return 1;
	}

	if (entry->msg_type == RADIUS_ACCT &&
	    radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
				    &acct_delay_time, &acct_delay_time_len,
				    NULL) == 0 &&
	    acct_delay_time_len == 4) {
		struct radius_hdr *hdr;
		u32 delay_time;

		/*
		 * Need to assign a new identifier since attribute contents
		 * changes.
		 */
		hdr = radius_msg_get_hdr(entry->msg);
		hdr->identifier = radius_client_get_id(radius);

		/* Update Acct-Delay-Time to show wait time in queue */
		delay_time = now - entry->first_try;
		WPA_PUT_BE32(acct_delay_time, delay_time);

		wpa_printf(MSG_DEBUG,
			   "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
			   delay_time);
		radius_msg_finish_acct(entry->msg, entry->shared_secret,
				       entry->shared_secret_len);
		if (radius->conf->msg_dumps)
			radius_msg_dump(entry->msg);
	}

	/* retransmit; remove entry if too many attempts */
	entry->attempts++;
	hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
		       radius_msg_get_hdr(entry->msg)->identifier);

	os_get_reltime(&entry->last_attempt);
	buf = radius_msg_get_buf(entry->msg);
	if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
		if (radius_client_handle_send_error(radius, s, entry->msg_type)
		    > 0)
			return 0;
	}

	entry->next_try = now + entry->next_wait;
	entry->next_wait *= 2;
	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
		wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
		return 1;
	}

	return 0;
}
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
		     int old_vlanid)
{
#ifndef CONFIG_NO_VLAN
	const char *iface;
	struct hostapd_vlan *vlan = NULL;
	int ret;

	/*
	 * 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");

	ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
	if (ret < 0) {
		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
			       "entry to vlan_id=%d", sta->vlan_id);
	}
	return ret;
#else /* CONFIG_NO_VLAN */
	return 0;
#endif /* CONFIG_NO_VLAN */
}
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
	struct radius_client_data *radius = eloop_ctx;
	struct hostapd_radius_servers *conf = radius->conf;
	struct os_time now;
	os_time_t first;
	struct radius_msg_list *entry, *prev, *tmp;
	int auth_failover = 0, acct_failover = 0;
	char abuf[50];

	entry = radius->msgs;
	if (!entry)
		return;

	os_get_time(&now);
	first = 0;

	prev = NULL;
	while (entry) {
		if (now.sec >= entry->next_try &&
		    radius_client_retransmit(radius, entry, now.sec)) {
			if (prev)
				prev->next = entry->next;
			else
				radius->msgs = entry->next;

			tmp = entry;
			entry = entry->next;
			radius_client_msg_free(tmp);
			radius->num_msgs--;
			continue;
		}

		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
			if (entry->msg_type == RADIUS_ACCT ||
			    entry->msg_type == RADIUS_ACCT_INTERIM)
				acct_failover++;
			else
				auth_failover++;
		}

		if (first == 0 || entry->next_try < first)
			first = entry->next_try;

		prev = entry;
		entry = entry->next;
	}

	if (radius->msgs) {
		if (first < now.sec)
			first = now.sec;
		eloop_register_timeout(first - now.sec, 0,
				       radius_client_timer, radius, NULL);
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
			       "retransmit in %ld seconds",
			       (long int) (first - now.sec));
	}

	if (auth_failover && conf->num_auth_servers > 1) {
		struct hostapd_radius_server *next, *old;
		old = conf->auth_server;
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_NOTICE,
			       "No response from Authentication server "
			       "%s:%d - failover",
			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
			       old->port);

		for (entry = radius->msgs; entry; entry = entry->next) {
			if (entry->msg_type == RADIUS_AUTH)
				old->timeouts++;
		}

		next = old + 1;
		if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
			next = conf->auth_servers;
		conf->auth_server = next;
		radius_change_server(radius, next, old,
				     radius->auth_serv_sock,
				     radius->auth_serv_sock6, 1);
	}

	if (acct_failover && conf->num_acct_servers > 1) {
		struct hostapd_radius_server *next, *old;
		old = conf->acct_server;
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_NOTICE,
			       "No response from Accounting server "
			       "%s:%d - failover",
			       hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
			       old->port);

		for (entry = radius->msgs; entry; entry = entry->next) {
			if (entry->msg_type == RADIUS_ACCT ||
			    entry->msg_type == RADIUS_ACCT_INTERIM)
				old->timeouts++;
		}

		next = old + 1;
		if (next > &conf->acct_servers[conf->num_acct_servers - 1])
			next = conf->acct_servers;
		conf->acct_server = next;
		radius_change_server(radius, next, old,
				     radius->acct_serv_sock,
				     radius->acct_serv_sock6, 0);
	}
}
示例#9
0
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;
    }
}
示例#10
0
文件: eapol_test.c 项目: OPSF/uClinux
/* Process the RADIUS frames from Authentication Server */
static RadiusRxResult
ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
			struct radius_msg *msg, struct radius_msg *req,
			u8 *shared_secret, size_t shared_secret_len,
			void *data)
{
#if 0
	u32 session_timeout, termination_action;
	int session_timeout_set;
	int acct_interim_interval;
#endif

#if 0
	sta = ap_get_sta_radius_identifier(hapd, msg->hdr->identifier);
	if (sta == NULL) {
		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not "
		      "find matching station for this RADIUS "
		      "message\n");
		return RADIUS_RX_UNKNOWN;
	}
#endif

	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
	 * present when packet contains an EAP-Message attribute */
	if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT &&
	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
				0) < 0 &&
	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
		wpa_printf(MSG_DEBUG, "Allowing RADIUS "
			      "Access-Reject without Message-Authenticator "
			      "since it does not include EAP-Message\n");
	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
				     req)) {
		printf("Incoming RADIUS packet did not have correct "
		       "Message-Authenticator - dropped\n");
		return RADIUS_RX_UNKNOWN;
	}

	if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
	    msg->hdr->code != RADIUS_CODE_ACCESS_REJECT &&
	    msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
		printf("Unknown RADIUS message code\n");
		return RADIUS_RX_UNKNOWN;
	}

	wpa_s->radius_identifier = -1;
	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station");

	if (wpa_s->last_recv_radius) {
		radius_msg_free(wpa_s->last_recv_radius);
		free(wpa_s->last_recv_radius);
	}

	wpa_s->last_recv_radius = msg;

#if 0
	session_timeout_set =
		!radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
					   &session_timeout);
	if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
				      &termination_action))
		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;

	if (hapd->conf->radius_acct_interim_interval == 0 &&
	    msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
	    radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
				      &acct_interim_interval) == 0) {
		if (acct_interim_interval < 60) {
			hostapd_logger(hapd, sta->addr,
				       HOSTAPD_MODULE_IEEE8021X,
				       HOSTAPD_LEVEL_INFO,
				       "ignored too small "
				       "Acct-Interim-Interval %d",
				       acct_interim_interval);
		} else
			sta->acct_interim_interval = acct_interim_interval;
	}


	switch (msg->hdr->code) {
	case RADIUS_CODE_ACCESS_ACCEPT:
		/* draft-congdon-radius-8021x-22.txt, Ch. 3.17 */
		if (session_timeout_set &&
			termination_action ==
		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
			sta->eapol_sm->reauth_timer.reAuthPeriod =
				session_timeout;
		} else if (session_timeout_set)
			ap_sta_session_timeout(hapd, sta, session_timeout);

		sta->eapol_sm->be_auth.aSuccess = TRUE;
		ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
				    shared_secret_len);
		if (sta->eapol_sm->keyAvailable) {
			pmksa_cache_add(hapd, sta, sta->eapol_key_crypt,
					session_timeout_set ?
					session_timeout : -1);
		}
		break;
	case RADIUS_CODE_ACCESS_REJECT:
		sta->eapol_sm->be_auth.aFail = TRUE;
		break;
	case RADIUS_CODE_ACCESS_CHALLENGE:
		if (session_timeout_set) {
			/* RFC 2869, Ch. 2.3.2
			 * draft-congdon-radius-8021x-22.txt, Ch. 3.17 */
			sta->eapol_sm->be_auth.suppTimeout = session_timeout;
		}
		sta->eapol_sm->be_auth.aReq = TRUE;
		break;
	}
#else

	switch (msg->hdr->code) {
	case RADIUS_CODE_ACCESS_ACCEPT:
		wpa_s->radius_access_accept_received = 1;
		ieee802_1x_get_keys(wpa_s, msg, req, shared_secret,
				    shared_secret_len);
		break;
	case RADIUS_CODE_ACCESS_REJECT:
		wpa_s->radius_access_reject_received = 1;
		break;
	}
#endif

	ieee802_1x_decapsulate_radius(wpa_s);

	/* eapol_sm_step(sta->eapol_sm); */

	if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT ||
	    msg->hdr->code == RADIUS_CODE_ACCESS_REJECT) {
		eloop_terminate();
	}

	return RADIUS_RX_QUEUED;
}
示例#11
0
/**
 * hostapd_select_hw_mode - Select the hardware mode
 * @iface: Pointer to interface data.
 * Returns: 0 on success, -1 on failure
 *
 * Sets up the hardware mode, channel, rates, and passive scanning
 * based on the configuration.
 */
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
	int i, j, ok, ret;

	if (iface->num_hw_features < 1)
		return -1;

	iface->current_mode = NULL;
	for (i = 0; i < iface->num_hw_features; i++) {
		struct hostapd_hw_modes *mode = &iface->hw_features[i];
		if (mode->mode == (int) iface->conf->hw_mode) {
			iface->current_mode = mode;
			break;
		}
	}

	if (iface->current_mode == NULL) {
		wpa_printf(MSG_ERROR, "Hardware does not support configured "
			   "mode");
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured mode "
			       "(%d)", (int) iface->conf->hw_mode);
		return -1;
	}

	ok = 0;
	for (j = 0; j < iface->current_mode->num_channels; j++) {
		struct hostapd_channel_data *chan =
			&iface->current_mode->channels[j];
		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
		    (chan->chan == iface->conf->channel)) {
			ok = 1;
			break;
		}
	}
	if (ok == 0 && iface->conf->channel != 0) {
		hostapd_logger(iface->bss[0], NULL,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Configured channel (%d) not found from the "
			       "channel list of current mode (%d) %s",
			       iface->conf->channel,
			       iface->current_mode->mode,
			       hostapd_hw_mode_txt(iface->current_mode->mode));
		iface->current_mode = NULL;
	}

	if (iface->current_mode == NULL) {
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured channel");
		return -1;
	}

	if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
		wpa_printf(MSG_ERROR, "Failed to prepare rates table.");
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
					   HOSTAPD_LEVEL_WARNING,
					   "Failed to prepare rates table.");
		return -1;
	}

	ret = hostapd_passive_scan(iface->bss[0], 0,
				   iface->conf->passive_scan_mode,
				   iface->conf->passive_scan_interval,
				   iface->conf->passive_scan_listen,
				   NULL, NULL);
	if (ret) {
		if (ret == -1) {
			wpa_printf(MSG_DEBUG, "Passive scanning not "
				   "supported");
		} else {
			wpa_printf(MSG_ERROR, "Could not set passive "
				   "scanning: %s", strerror(ret));
		}
		ret = 0;
	}

	return ret;
}
示例#12
0
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#ifndef CONFIG_NO_VLAN
	const char *iface;
	struct hostapd_vlan *vlan = NULL;
	int ret;
	int old_vlanid = sta->vlan_id_bound;

	iface = hapd->conf->iface;
	if (hapd->conf->ssid.vlan[0])
		iface = hapd->conf->ssid.vlan;

	if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
		sta->vlan_id = 0;
	else if (sta->vlan_id > 0) {
		struct hostapd_vlan *wildcard_vlan = NULL;
		vlan = hapd->conf->vlan;
		while (vlan) {
			if (vlan->vlan_id == sta->vlan_id)
				break;
			if (vlan->vlan_id == VLAN_ID_WILDCARD)
				wildcard_vlan = vlan;
			vlan = vlan->next;
		}
		if (!vlan)
			vlan = wildcard_vlan;
		if (vlan)
			iface = vlan->ifname;
	}

	/*
	 * Do not increment ref counters if the VLAN ID remains same, but do
	 * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
	 * have been called before.
	 */
	if (sta->vlan_id == old_vlanid)
		goto skip_counting;

	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);
		ret = -1;
		goto done;
	} 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);
			ret = -1;
			goto done;
		}

		iface = vlan->ifname;
		if (vlan_setup_encryption_dyn(hapd, 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 (vlan->dynamic_vlan > 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, 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);
		}
	}

	/* ref counters have been increased, so mark the station */
	sta->vlan_id_bound = sta->vlan_id;

skip_counting:
	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");

	ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
	if (ret < 0) {
		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
			       "entry to vlan_id=%d", sta->vlan_id);
	}

	/* During 1x reauth, if the vlan id changes, then remove the old id. */
	if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
		vlan_remove_dynamic(hapd, old_vlanid);
done:

	return ret;
#else /* CONFIG_NO_VLAN */
	return 0;
#endif /* CONFIG_NO_VLAN */
}
static int
radius_change_server(struct radius_client_data *radius,
		     struct hostapd_radius_server *nserv,
		     struct hostapd_radius_server *oserv,
		     int sock, int sock6, int auth)
{
	struct sockaddr_in serv;
#ifdef CONFIG_IPV6
	struct sockaddr_in6 serv6;
#endif /* CONFIG_IPV6 */
	struct sockaddr *addr;
	socklen_t addrlen;
	char abuf[50];
	int sel_sock;
	struct radius_msg_list *entry;

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_INFO,
		       "%s server %s:%d",
		       auth ? "Authentication" : "Accounting",
		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
		       nserv->port);

	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
		      nserv->shared_secret_len) != 0) {
		/* Pending RADIUS packets used different shared secret, so
		 * they need to be modified. Update accounting message
		 * authenticators here. Authentication messages are removed
		 * since they would require more changes and the new RADIUS
		 * server may not be prepared to receive them anyway due to
		 * missing state information. Client will likely retry
		 * authentication, so this should not be an issue. */
		if (auth)
			radius_client_flush(radius, 1);
		else {
			radius_client_update_acct_msgs(
				radius, nserv->shared_secret,
				nserv->shared_secret_len);
		}
	}

	/* Reset retry counters for the new server */
	for (entry = radius->msgs; entry; entry = entry->next) {
		if ((auth && entry->msg_type != RADIUS_AUTH) ||
		    (!auth && entry->msg_type != RADIUS_ACCT))
			continue;
		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
		entry->attempts = 0;
		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
	}

	if (radius->msgs) {
		eloop_cancel_timeout(radius_client_timer, radius, NULL);
		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
				       radius_client_timer, radius, NULL);
	}

	switch (nserv->addr.af) {
	case AF_INET:
		os_memset(&serv, 0, sizeof(serv));
		serv.sin_family = AF_INET;
		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
		serv.sin_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv;
		addrlen = sizeof(serv);
		sel_sock = sock;
		break;
#ifdef CONFIG_IPV6
	case AF_INET6:
		os_memset(&serv6, 0, sizeof(serv6));
		serv6.sin6_family = AF_INET6;
		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
			  sizeof(struct in6_addr));
		serv6.sin6_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv6;
		addrlen = sizeof(serv6);
		sel_sock = sock6;
		break;
#endif /* CONFIG_IPV6 */
	default:
		return -1;
	}

	if (connect(sel_sock, addr, addrlen) < 0) {
		perror("connect[radius]");
		return -1;
	}

	if (auth)
		radius->auth_sock = sel_sock;
	else
		radius->acct_sock = sel_sock;

	return 0;
}
示例#14
0
void hostapd_2040_coex_action(struct hostapd_data *hapd,
			      const struct ieee80211_mgmt *mgmt, size_t len)
{
	struct hostapd_iface *iface = hapd->iface;
	struct ieee80211_2040_bss_coex_ie *bc_ie;
	struct ieee80211_2040_intol_chan_report *ic_report;
	int is_ht40_allowed = 1;
	int i;
	const u8 *start = (const u8 *) mgmt;
	const u8 *data = start + IEEE80211_HDRLEN + 2;

	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
		       mgmt->u.action.u.public_action.action);

	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
		return;

	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
		return;

	bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
	if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
	    bc_ie->length < 1) {
		wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
			   bc_ie->element_id, bc_ie->length);
		return;
	}
	if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
		return;
	data += 2 + bc_ie->length;

	wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
		   bc_ie->coex_param);
	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
		hostapd_logger(hapd, mgmt->sa,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "20 MHz BSS width request bit is set in BSS coexistence information field");
		is_ht40_allowed = 0;
	}

	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
		hostapd_logger(hapd, mgmt->sa,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "40 MHz intolerant bit is set in BSS coexistence information field");
		is_ht40_allowed = 0;
	}

	if (start + len - data >= 3 &&
	    data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
		u8 ielen = data[1];

		if (ielen > start + len - data - 2)
			return;
		ic_report = (struct ieee80211_2040_intol_chan_report *) data;
		wpa_printf(MSG_DEBUG,
			   "20/40 BSS Intolerant Channel Report: Operating Class %u",
			   ic_report->op_class);

		/* Go through the channel report to find any BSS there in the
		 * affected channel range */
		for (i = 0; i < ielen - 1; i++) {
			u8 chan = ic_report->variable[i];

			if (is_40_allowed(iface, chan))
				continue;
			hostapd_logger(hapd, mgmt->sa,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_DEBUG,
				       "20_40_INTOLERANT channel %d reported",
				       chan);
			is_ht40_allowed = 0;
		}
	}
	wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
		   is_ht40_allowed, iface->num_sta_ht40_intolerant);

	if (!is_ht40_allowed &&
	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
		if (iface->conf->secondary_channel) {
			hostapd_logger(hapd, mgmt->sa,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_INFO,
				       "Switching to 20 MHz operation");
			iface->conf->secondary_channel = 0;
			ieee802_11_set_beacons(iface);
		}
		if (!iface->num_sta_ht40_intolerant &&
		    iface->conf->obss_interval) {
			unsigned int delay_time;
			delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
				iface->conf->obss_interval;
			eloop_cancel_timeout(ap_ht2040_timeout, hapd->iface,
					     NULL);
			eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
					       hapd->iface, NULL);
			wpa_printf(MSG_DEBUG,
				   "Reschedule HT 20/40 timeout to occur in %u seconds",
				   delay_time);
		}
	}
}
示例#15
0
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(&param, 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, &param, sizeof(param))) {
        printf("Could not add station to kernel driver.\n");
    }

    if (new_assoc)
        hostapd_new_assoc_sta(hapd, sta);

    if (sta->eapol_sm)
        sta->eapol_sm->portEnabled = TRUE;

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;
    }
}
示例#16
0
/**
 * hostapd_select_hw_mode - Select the hardware mode
 * @iface: Pointer to interface data.
 * Returns: 0 on success, < 0 on failure
 *
 * Sets up the hardware mode, channel, rates, and passive scanning
 * based on the configuration.
 */
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
	int i, j, ok;

	if (iface->num_hw_features < 1)
		return -1;

	iface->current_mode = NULL;
	for (i = 0; i < iface->num_hw_features; i++) {
		struct hostapd_hw_modes *mode = &iface->hw_features[i];
		if (mode->mode == iface->conf->hw_mode) {
			iface->current_mode = mode;
			break;
		}
	}

	if (iface->current_mode == NULL) {
		wpa_printf(MSG_ERROR, "Hardware does not support configured "
			   "mode");
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured mode "
			       "(%d) (hw_mode in hostapd.conf)",
			       (int) iface->conf->hw_mode);
		return -2;
	}

	ok = 0;
	for (j = 0; j < iface->current_mode->num_channels; j++) {
		struct hostapd_channel_data *chan =
			&iface->current_mode->channels[j];
		if (chan->chan == iface->conf->channel) {
			if (chan->flag & HOSTAPD_CHAN_DISABLED) {
				wpa_printf(MSG_ERROR,
					   "channel [%i] (%i) is disabled for "
					   "use in AP mode, flags: 0x%x%s%s%s",
					   j, chan->chan, chan->flag,
					   chan->flag & HOSTAPD_CHAN_NO_IBSS ?
					   " NO-IBSS" : "",
					   chan->flag &
					   HOSTAPD_CHAN_PASSIVE_SCAN ?
					   " PASSIVE-SCAN" : "",
					   chan->flag & HOSTAPD_CHAN_RADAR ?
					   " RADAR" : "");
			} else {
				ok = 1;
				break;
			}
		}
	}
	if (ok && iface->conf->secondary_channel) {
		int sec_ok = 0;
		int sec_chan = iface->conf->channel +
			iface->conf->secondary_channel * 4;
		for (j = 0; j < iface->current_mode->num_channels; j++) {
			struct hostapd_channel_data *chan =
				&iface->current_mode->channels[j];
			if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
			    (chan->chan == sec_chan)) {
				sec_ok = 1;
				break;
			}
		}
		if (!sec_ok) {
			hostapd_logger(iface->bss[0], NULL,
				       HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_WARNING,
				       "Configured HT40 secondary channel "
				       "(%d) not found from the channel list "
				       "of current mode (%d) %s",
				       sec_chan, iface->current_mode->mode,
				       hostapd_hw_mode_txt(
					       iface->current_mode->mode));
			ok = 0;
		}
	}
	if (iface->conf->channel == 0) {
		/* TODO: could request a scan of neighboring BSSes and select
		 * the channel automatically */
		wpa_printf(MSG_ERROR, "Channel not configured "
			   "(hw_mode/channel in hostapd.conf)");
		return -3;
	}
	if (ok == 0 && iface->conf->channel != 0) {
		hostapd_logger(iface->bss[0], NULL,
			       HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Configured channel (%d) not found from the "
			       "channel list of current mode (%d) %s",
			       iface->conf->channel,
			       iface->current_mode->mode,
			       hostapd_hw_mode_txt(iface->current_mode->mode));
		iface->current_mode = NULL;
	}

	if (iface->current_mode == NULL) {
		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "Hardware does not support configured channel");
		return -4;
	}

	return 0;
}
示例#17
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;
}
示例#18
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);
}
/**
 * ap_handle_timer - Per STA timer handler
 * @eloop_ctx: struct hostapd_data *
 * @timeout_ctx: struct sta_info *
 *
 * This function is called to check station activity and to remove inactive
 * stations.
 */
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
{
	struct hostapd_data *hapd = eloop_ctx;
	struct sta_info *sta = timeout_ctx;
	unsigned long next_time = 0;

	wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
		   __func__, MAC2STR(sta->addr), sta->flags,
		   sta->timeout_next);
	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;
		/*
		 * Add random value to timeout so that we don't end up bouncing
		 * all stations at the same time if we have lots of associated
		 * stations that are idle (but keep re-associating).
		 */
		int fuzz = os_random() % 20;
		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
		if (inactive_sec == -1) {
			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
				"Check inactivity: Could not "
				"get station info from kernel driver for "
				MACSTR, MAC2STR(sta->addr));
			/*
			 * The driver may not support this functionality.
			 * Anyway, try again after the next inactivity timeout,
			 * but do not disconnect the station now.
			 */
			next_time = hapd->conf->ap_max_inactivity + fuzz;
		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
			   sta->flags & WLAN_STA_ASSOC) {
			/* station activity detected; reset timeout state */
			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
				"Station " MACSTR " has been active %is ago",
				MAC2STR(sta->addr), inactive_sec);
			sta->timeout_next = STA_NULLFUNC;
			next_time = hapd->conf->ap_max_inactivity + fuzz -
				inactive_sec;
		} else {
			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
				"Station " MACSTR " has been "
				"inactive too long: %d sec, max allowed: %d",
				MAC2STR(sta->addr), inactive_sec,
				hapd->conf->ap_max_inactivity);

			if (hapd->conf->skip_inactivity_poll)
				sta->timeout_next = STA_DISASSOC;
		}
	}

	if ((sta->flags & WLAN_STA_ASSOC) &&
	    sta->timeout_next == STA_DISASSOC &&
	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
	    !hapd->conf->skip_inactivity_poll) {
		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
			" has ACKed data poll", MAC2STR(sta->addr));
		/* data nullfunc frame poll did not produce TX errors; assume
		 * station ACKed it */
		sta->timeout_next = STA_NULLFUNC;
		next_time = hapd->conf->ap_max_inactivity;
	}

	if (next_time) {
		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
			   "for " MACSTR " (%lu seconds)",
			   __func__, MAC2STR(sta->addr), 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)) {
		wpa_printf(MSG_DEBUG, "  Polling STA");
		sta->flags |= WLAN_STA_PENDING_POLL;
		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
					sta->flags & WLAN_STA_WMM);
	} else if (sta->timeout_next != STA_REMOVE) {
		int deauth = sta->timeout_next == STA_DEAUTH;

		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
			"Timeout, sending %s info to STA " MACSTR,
			deauth ? "deauthentication" : "disassociation",
			MAC2STR(sta->addr));

		if (deauth) {
			hostapd_drv_sta_deauth(
				hapd, sta->addr,
				WLAN_REASON_PREV_AUTH_NOT_VALID);
		} else {
			hostapd_drv_sta_disassoc(
				hapd, sta->addr,
				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
		}
	}

	switch (sta->timeout_next) {
	case STA_NULLFUNC:
		sta->timeout_next = STA_DISASSOC;
		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
			   "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
			   __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
		eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
				       hapd, sta);
		break;
	case STA_DISASSOC:
		ap_sta_set_authorized(hapd, sta, 0);
		sta->flags &= ~WLAN_STA_ASSOC;
		ieee802_1x_notify_port_enabled(sta->eapol_sm, 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;
		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
			   "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
			   __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
		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:
		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
			       "inactivity (timer DEAUTH/REMOVE)");
		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;
	}
}
示例#20
0
static void handle_assoc(hostapd *hapd, struct ieee80211_mgmt *mgmt,
                         size_t len, int reassoc)
{
    u16 capab_info, listen_interval;
    u16 resp = WLAN_STATUS_SUCCESS;
    u8 *pos, *wpa_ie;
    size_t wpa_ie_len;
    int send_deauth = 0, send_len, left, i;
    struct sta_info *sta;
    struct ieee802_11_elems elems;

    if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
                                  sizeof(mgmt->u.assoc_req))) {
        printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
               "\n", reassoc, (unsigned long) len);
        return;
    }

    if (reassoc) {
        capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
        listen_interval = le_to_host16(
                              mgmt->u.reassoc_req.listen_interval);
        HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
                      "reassociation request: STA=" MACSTR
                      " capab_info=0x%02x "
                      "listen_interval=%d current_ap=" MACSTR "\n",
                      MAC2STR(mgmt->sa), capab_info, listen_interval,
                      MAC2STR(mgmt->u.reassoc_req.current_ap));
        left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
        pos = mgmt->u.reassoc_req.variable;
    } else {
        capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
        listen_interval = le_to_host16(
                              mgmt->u.assoc_req.listen_interval);
        HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
                      "association request: STA=" MACSTR
                      " capab_info=0x%02x listen_interval=%d\n",
                      MAC2STR(mgmt->sa), capab_info, listen_interval);
        left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
        pos = mgmt->u.assoc_req.variable;
    }

    sta = ap_get_sta(hapd, mgmt->sa);
    if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
        printf("STA " MACSTR " trying to associate before "
               "authentication\n", MAC2STR(mgmt->sa));
        if (sta) {
            printf("  sta: addr=" MACSTR " aid=%d flags=0x%04x\n",
                   MAC2STR(sta->addr), sta->aid, sta->flags);
        }
        send_deauth = 1;
        resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
        goto fail;
    }

    if (hapd->tkip_countermeasures) {
        resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
        goto fail;
    }

    sta->capability = capab_info;

    /* followed by SSID and Supported rates */
    if (ieee802_11_parse_elems(hapd, pos, left, &elems, 1) == ParseFailed
            || !elems.ssid) {
        printf("STA " MACSTR " sent invalid association request\n",
               MAC2STR(sta->addr));
        resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
        goto fail;
    }

    if (elems.ssid_len != hapd->conf->ssid_len ||
            memcmp(elems.ssid, hapd->conf->ssid, elems.ssid_len) != 0) {
        printf("Station " MACSTR " tried to associate with "
               "unknown SSID '", MAC2STR(sta->addr));
        ieee802_11_print_ssid(elems.ssid, elems.ssid_len);
        printf("'\n");
        resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
        goto fail;
    }

    if (elems.supp_rates) {
        if (elems.supp_rates_len > sizeof(sta->supported_rates)) {
            printf("STA " MACSTR ": Invalid supported rates "
                   "element length %d\n", MAC2STR(sta->addr),
                   elems.supp_rates_len);
            resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
            goto fail;
        }

        memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
        memcpy(sta->supported_rates, elems.supp_rates,
               elems.supp_rates_len);

        sta->tx_supp_rates = 0;
        for (i = 0; i < elems.supp_rates_len; i++) {
            if ((sta->supported_rates[i] & 0x7f) == 2)
                sta->tx_supp_rates |= WLAN_RATE_1M;
            if ((sta->supported_rates[i] & 0x7f) == 4)
                sta->tx_supp_rates |= WLAN_RATE_2M;
            if ((sta->supported_rates[i] & 0x7f) == 11)
                sta->tx_supp_rates |= WLAN_RATE_5M5;
            if ((sta->supported_rates[i] & 0x7f) == 22)
                sta->tx_supp_rates |= WLAN_RATE_11M;
        }
    } else
        sta->tx_supp_rates = 0xff;

    if ((hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) && elems.rsn_ie) {
        wpa_ie = elems.rsn_ie;
        wpa_ie_len = elems.rsn_ie_len;
    } else if ((hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA) &&
               elems.wpa_ie) {
        wpa_ie = elems.wpa_ie;
        wpa_ie_len = elems.wpa_ie_len;
    } else {
        wpa_ie = NULL;
        wpa_ie_len = 0;
    }
    if (hapd->conf->wpa && wpa_ie == NULL) {
        printf("STA " MACSTR ": No WPA/RSN IE in association "
               "request\n", MAC2STR(sta->addr));
        resp = WLAN_STATUS_INVALID_IE;
        goto fail;
    }

    if (hapd->conf->wpa) {
        int res;
        wpa_ie -= 2;
        wpa_ie_len += 2;
        res = wpa_validate_wpa_ie(hapd, sta, wpa_ie, wpa_ie_len,
                                  elems.rsn_ie ?
                                  HOSTAPD_WPA_VERSION_WPA2 :
                                  HOSTAPD_WPA_VERSION_WPA);
        if (res == WPA_INVALID_GROUP)
            resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
        else if (res == WPA_INVALID_PAIRWISE)
            resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
        else if (res == WPA_INVALID_AKMP)
            resp = WLAN_STATUS_AKMP_NOT_VALID;
        else if (res != WPA_IE_OK)
            resp = WLAN_STATUS_INVALID_IE;
        if (resp != WLAN_STATUS_SUCCESS)
            goto fail;
        free(sta->wpa_ie);
        sta->wpa_ie = malloc(wpa_ie_len);
        if (sta->wpa_ie == NULL) {
            resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
            goto fail;
        }
        sta->wpa_ie_len = wpa_ie_len;
        memcpy(sta->wpa_ie, wpa_ie, wpa_ie_len);
    }

    /* get a unique AID */
    if (sta->aid > 0) {
        HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
                      "  old AID %d\n", sta->aid);
    } else {
        for (sta->aid = 1; sta->aid <= MAX_AID_TABLE_SIZE; sta->aid++)
            if (hapd->sta_aid[sta->aid - 1] == NULL)
                break;
        if (sta->aid > MAX_AID_TABLE_SIZE) {
            sta->aid = 0;
            resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
            printf("  no room for more AIDs\n");
            goto fail;
        } else {
            hapd->sta_aid[sta->aid - 1] = sta;
            HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
                          "  new AID %d\n", sta->aid);
        }
    }

    hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
                   HOSTAPD_LEVEL_DEBUG,
                   "association OK (aid %d)", sta->aid);
    /* Station will be marked associated, after it acknowledges AssocResp
     */

    if (sta->last_assoc_req)
        free(sta->last_assoc_req);
    sta->last_assoc_req = (struct ieee80211_mgmt *) malloc(len);
    if (sta->last_assoc_req)
        memcpy(sta->last_assoc_req, mgmt, len);

    /* Make sure that the previously registered inactivity timer will not
     * remove the STA immediately. */
    sta->timeout_next = STA_NULLFUNC;

fail:

    /* use the queued buffer for transmission because it is large enough
     * and not needed anymore */
    mgmt->frame_control =
        IEEE80211_FC(WLAN_FC_TYPE_MGMT,
                     (send_deauth ? WLAN_FC_STYPE_DEAUTH :
                      (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
                       WLAN_FC_STYPE_ASSOC_RESP)));
    memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
    memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
    /* Addr3 = BSSID - already set */

    send_len = IEEE80211_HDRLEN;
    if (send_deauth) {
        send_len += sizeof(mgmt->u.deauth);
        mgmt->u.deauth.reason_code = host_to_le16(resp);
    } else {
        u8 *p;
        send_len += sizeof(mgmt->u.assoc_resp);
        mgmt->u.assoc_resp.capab_info =
            host_to_le16(hostapd_own_capab_info(hapd));
        mgmt->u.assoc_resp.status_code = host_to_le16(resp);
        mgmt->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
                                              | BIT(14) | BIT(15));
        /* Supported rates */
        p = hostapd_eid_supp_rates(hapd, mgmt->u.assoc_resp.variable);
        send_len += p - mgmt->u.assoc_resp.variable;

        /* Request TX callback */
        mgmt->frame_control |= host_to_le16(BIT(1));
    }

    if (hostapd_send_mgmt_frame(hapd, mgmt, send_len, 0) < 0)
        perror("handle_assoc: send");
}
示例#21
0
static int
radius_change_server(struct radius_client_data *radius,
		     struct hostapd_radius_server *nserv,
		     struct hostapd_radius_server *oserv,
		     int sock, int sock6, int auth)
{
	struct sockaddr_in serv, claddr;
#ifdef CONFIG_IPV6
	struct sockaddr_in6 serv6, claddr6;
#endif /* CONFIG_IPV6 */
	struct sockaddr *addr, *cl_addr;
	socklen_t addrlen, claddrlen;
	char abuf[50];
	int sel_sock;
	struct radius_msg_list *entry;
	struct hostapd_radius_servers *conf = radius->conf;
	struct sockaddr_in disconnect_addr = {
		.sin_family = AF_UNSPEC,
	};

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_INFO,
		       "%s server %s:%d",
		       auth ? "Authentication" : "Accounting",
		       hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
		       nserv->port);

	if (oserv && oserv == nserv) {
		/* Reconnect to same server, flush */
		if (auth)
			radius_client_flush(radius, 1);
	}

	if (oserv && oserv != nserv &&
	    (nserv->shared_secret_len != oserv->shared_secret_len ||
	     os_memcmp(nserv->shared_secret, oserv->shared_secret,
		       nserv->shared_secret_len) != 0)) {
		/* Pending RADIUS packets used different shared secret, so
		 * they need to be modified. Update accounting message
		 * authenticators here. Authentication messages are removed
		 * since they would require more changes and the new RADIUS
		 * server may not be prepared to receive them anyway due to
		 * missing state information. Client will likely retry
		 * authentication, so this should not be an issue. */
		if (auth)
			radius_client_flush(radius, 1);
		else {
			radius_client_update_acct_msgs(
				radius, nserv->shared_secret,
				nserv->shared_secret_len);
		}
	}

	/* Reset retry counters for the new server */
	for (entry = radius->msgs; oserv && oserv != nserv && entry;
	     entry = entry->next) {
		if ((auth && entry->msg_type != RADIUS_AUTH) ||
		    (!auth && entry->msg_type != RADIUS_ACCT))
			continue;
		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
		entry->attempts = 0;
		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
	}

	if (radius->msgs) {
		eloop_cancel_timeout(radius_client_timer, radius, NULL);
		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
				       radius_client_timer, radius, NULL);
	}

	switch (nserv->addr.af) {
	case AF_INET:
		os_memset(&serv, 0, sizeof(serv));
		serv.sin_family = AF_INET;
		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
		serv.sin_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv;
		addrlen = sizeof(serv);
		sel_sock = sock;
		break;
#ifdef CONFIG_IPV6
	case AF_INET6:
		os_memset(&serv6, 0, sizeof(serv6));
		serv6.sin6_family = AF_INET6;
		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
			  sizeof(struct in6_addr));
		serv6.sin6_port = htons(nserv->port);
		addr = (struct sockaddr *) &serv6;
		addrlen = sizeof(serv6);
		sel_sock = sock6;
		break;
#endif /* CONFIG_IPV6 */
	default:
		return -1;
	}

	if (sel_sock < 0) {
		wpa_printf(MSG_INFO,
			   "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
			   nserv->addr.af, sock, sock6, auth);
		return -1;
	}

	if (conf->force_client_addr) {
		switch (conf->client_addr.af) {
		case AF_INET:
			os_memset(&claddr, 0, sizeof(claddr));
			claddr.sin_family = AF_INET;
			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
			claddr.sin_port = htons(0);
			cl_addr = (struct sockaddr *) &claddr;
			claddrlen = sizeof(claddr);
			break;
#ifdef CONFIG_IPV6
		case AF_INET6:
			os_memset(&claddr6, 0, sizeof(claddr6));
			claddr6.sin6_family = AF_INET6;
			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
				  sizeof(struct in6_addr));
			claddr6.sin6_port = htons(0);
			cl_addr = (struct sockaddr *) &claddr6;
			claddrlen = sizeof(claddr6);
			break;
#endif /* CONFIG_IPV6 */
		default:
			return -1;
		}

		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
			wpa_printf(MSG_INFO, "bind[radius]: %s",
				   strerror(errno));
			return -1;
		}
	}

	/* Force a reconnect by disconnecting the socket first */
	if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
		    sizeof(disconnect_addr)) < 0)
		wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));

	if (connect(sel_sock, addr, addrlen) < 0) {
		wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
		return -1;
	}

#ifndef CONFIG_NATIVE_WINDOWS
	switch (nserv->addr.af) {
	case AF_INET:
		claddrlen = sizeof(claddr);
		if (getsockname(sel_sock, (struct sockaddr *) &claddr,
				&claddrlen) == 0) {
			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
				   inet_ntoa(claddr.sin_addr),
				   ntohs(claddr.sin_port));
		}
		break;
#ifdef CONFIG_IPV6
	case AF_INET6: {
		claddrlen = sizeof(claddr6);
		if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
				&claddrlen) == 0) {
			wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
				   inet_ntop(AF_INET6, &claddr6.sin6_addr,
					     abuf, sizeof(abuf)),
				   ntohs(claddr6.sin6_port));
		}
		break;
	}
#endif /* CONFIG_IPV6 */
	}
#endif /* CONFIG_NATIVE_WINDOWS */

	if (auth)
		radius->auth_sock = sel_sock;
	else
		radius->acct_sock = sel_sock;

	return 0;
}
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
                        const u8 *req_ies, size_t req_ies_len, int reassoc)
{
    struct sta_info *sta;
    int new_assoc, res;
    struct ieee802_11_elems elems;
    const u8 *ie;
    size_t ielen;
#ifdef CONFIG_IEEE80211R
    u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
    u8 *p = buf;
#endif /* CONFIG_IEEE80211R */
    u16 reason = WLAN_REASON_UNSPECIFIED;
    u16 status = WLAN_STATUS_SUCCESS;
    const u8 *p2p_dev_addr = NULL;

    if (addr == NULL) {
        /*
         * This could potentially happen with unexpected event from the
         * driver wrapper. This was seen at least in one case where the
         * driver ended up being set to station mode while hostapd was
         * running, so better make sure we stop processing such an
         * event here.
         */
        wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
                   "no address");
        return -1;
    }
    random_add_randomness(addr, ETH_ALEN);

    hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
                   HOSTAPD_LEVEL_INFO, "associated");

    ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
    if (elems.wps_ie) {
        ie = elems.wps_ie - 2;
        ielen = elems.wps_ie_len + 2;
        wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
    } else if (elems.rsn_ie) {
        ie = elems.rsn_ie - 2;
        ielen = elems.rsn_ie_len + 2;
        wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
    } else if (elems.wpa_ie) {
        ie = elems.wpa_ie - 2;
        ielen = elems.wpa_ie_len + 2;
        wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
    } else {
        ie = NULL;
        ielen = 0;
        wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
                   "(Re)AssocReq");
    }

    sta = ap_get_sta(hapd, addr);
    if (sta) {
        ap_sta_no_session_timeout(hapd, sta);
        accounting_sta_stop(hapd, sta);

        /*
         * Make sure that the previously registered inactivity timer
         * will not remove the STA immediately.
         */
        sta->timeout_next = STA_NULLFUNC;
    } else {
        sta = ap_sta_add(hapd, addr);
        if (sta == NULL) {
            hostapd_drv_sta_disassoc(hapd, addr,
                                     WLAN_REASON_DISASSOC_AP_BUSY);
            return -1;
        }
    }
    sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);

#ifdef CONFIG_P2P
    if (elems.p2p) {
        wpabuf_free(sta->p2p_ie);
        sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
                      P2P_IE_VENDOR_TYPE);
        if (sta->p2p_ie)
            p2p_dev_addr = p2p_get_go_dev_addr(sta->p2p_ie);
    }
#endif /* CONFIG_P2P */

#ifdef CONFIG_INTERWORKING
    if (elems.ext_capab && elems.ext_capab_len > 4) {
        if (elems.ext_capab[4] & 0x01)
            sta->qos_map_enabled = 1;
    }
#endif /* CONFIG_INTERWORKING */

#ifdef CONFIG_HS20
    wpabuf_free(sta->hs20_ie);
    if (elems.hs20 && elems.hs20_len > 4) {
        sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
                                         elems.hs20_len - 4);
    } else
        sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */

    if (hapd->conf->wpa) {
        if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
            if (hapd->conf->wps_state) {
                wpa_printf(MSG_DEBUG, "STA did not include "
                           "WPA/RSN IE in (Re)Association "
                           "Request - possible WPS use");
                sta->flags |= WLAN_STA_MAYBE_WPS;
                goto skip_wpa_check;
            }
#endif /* CONFIG_WPS */

            wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
            return -1;
        }
#ifdef CONFIG_WPS
        if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
                os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
            struct wpabuf *wps;
            sta->flags |= WLAN_STA_WPS;
            wps = ieee802_11_vendor_ie_concat(ie, ielen,
                                              WPS_IE_VENDOR_TYPE);
            if (wps) {
                if (wps_is_20(wps)) {
                    wpa_printf(MSG_DEBUG, "WPS: STA "
                               "supports WPS 2.0");
                    sta->flags |= WLAN_STA_WPS2;
                }
                wpabuf_free(wps);
            }
            goto skip_wpa_check;
        }
#endif /* CONFIG_WPS */

        if (sta->wpa_sm == NULL)
            sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
                                            sta->addr,
                                            p2p_dev_addr);
        if (sta->wpa_sm == NULL) {
            wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
                       "machine");
            return -1;
        }
        res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
                                  ie, ielen,
                                  elems.mdie, elems.mdie_len);
        if (res != WPA_IE_OK) {
            wpa_printf(MSG_DEBUG, "WPA/RSN information element "
                       "rejected? (res %u)", res);
            wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
            if (res == WPA_INVALID_GROUP) {
                reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
                status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
            } else if (res == WPA_INVALID_PAIRWISE) {
                reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
                status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
            } else if (res == WPA_INVALID_AKMP) {
                reason = WLAN_REASON_AKMP_NOT_VALID;
                status = WLAN_STATUS_AKMP_NOT_VALID;
            }
#ifdef CONFIG_IEEE80211W
            else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
                reason = WLAN_REASON_INVALID_IE;
                status = WLAN_STATUS_INVALID_IE;
            } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
                reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
                status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
            }
#endif /* CONFIG_IEEE80211W */
            else {
                reason = WLAN_REASON_INVALID_IE;
                status = WLAN_STATUS_INVALID_IE;
            }
            goto fail;
        }
#ifdef CONFIG_IEEE80211W
        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 &&
                (sta->auth_alg != WLAN_AUTH_FT)) {
            /*
             * 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->sa_query_count == 0)
                ap_sta_start_sa_query(hapd, sta);

#ifdef CONFIG_IEEE80211R
            status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;

            p = hostapd_eid_assoc_comeback_time(hapd, sta, p);

            hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
                              p - buf);
#endif /* CONFIG_IEEE80211R */
            return 0;
        }

        if (wpa_auth_uses_mfp(sta->wpa_sm))
            sta->flags |= WLAN_STA_MFP;
        else
            sta->flags &= ~WLAN_STA_MFP;
#endif /* CONFIG_IEEE80211W */

#ifdef CONFIG_IEEE80211R
        if (sta->auth_alg == WLAN_AUTH_FT) {
            status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
                                             req_ies_len);
            if (status != WLAN_STATUS_SUCCESS) {
                if (status == WLAN_STATUS_INVALID_PMKID)
                    reason = WLAN_REASON_INVALID_IE;
                if (status == WLAN_STATUS_INVALID_MDIE)
                    reason = WLAN_REASON_INVALID_IE;
                if (status == WLAN_STATUS_INVALID_FTIE)
                    reason = WLAN_REASON_INVALID_IE;
                goto fail;
            }
        }
#endif /* CONFIG_IEEE80211R */
    } else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
        struct wpabuf *wps;
        if (req_ies)
            wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
                                              WPS_IE_VENDOR_TYPE);
        else
            wps = NULL;
#ifdef CONFIG_WPS_STRICT
        if (wps && wps_validate_assoc_req(wps) < 0) {
            reason = WLAN_REASON_INVALID_IE;
            status = WLAN_STATUS_INVALID_IE;
            wpabuf_free(wps);
            goto fail;
        }
#endif /* CONFIG_WPS_STRICT */
        if (wps) {
            sta->flags |= WLAN_STA_WPS;
            if (wps_is_20(wps)) {
                wpa_printf(MSG_DEBUG, "WPS: STA supports "
                           "WPS 2.0");
                sta->flags |= WLAN_STA_WPS2;
            }
        } else
            sta->flags |= WLAN_STA_MAYBE_WPS;
        wpabuf_free(wps);
#endif /* CONFIG_WPS */
    }
#ifdef CONFIG_WPS
skip_wpa_check:
#endif /* CONFIG_WPS */

#ifdef CONFIG_IEEE80211R
    p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
                                    sta->auth_alg, req_ies, req_ies_len);

    hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#else /* CONFIG_IEEE80211R */
    /* Keep compiler silent about unused variables */
    if (status) {
    }
#endif /* CONFIG_IEEE80211R */

    new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
    sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;

    if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
        wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
    else
        wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);

    hostapd_new_assoc_sta(hapd, sta, !new_assoc);

    ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);

#ifdef CONFIG_P2P
    if (req_ies) {
        p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
                              req_ies, req_ies_len);
    }
#endif /* CONFIG_P2P */

    return 0;

fail:
#ifdef CONFIG_IEEE80211R
    hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
#endif /* CONFIG_IEEE80211R */
    hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
    ap_free_sta(hapd, sta);
    return -1;
}
示例#23
0
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
	struct radius_client_data *radius = eloop_ctx;
	struct os_reltime now;
	os_time_t first;
	struct radius_msg_list *entry, *prev, *tmp;
	int auth_failover = 0, acct_failover = 0;
	size_t prev_num_msgs;
	int s;

	entry = radius->msgs;
	if (!entry)
		return;

	os_get_reltime(&now);
	first = 0;

	prev = NULL;
	while (entry) {
		prev_num_msgs = radius->num_msgs;
		if (now.sec >= entry->next_try &&
		    radius_client_retransmit(radius, entry, now.sec)) {
			if (prev)
				prev->next = entry->next;
			else
				radius->msgs = entry->next;

			tmp = entry;
			entry = entry->next;
			radius_client_msg_free(tmp);
			radius->num_msgs--;
			continue;
		}

		if (prev_num_msgs != radius->num_msgs) {
			wpa_printf(MSG_DEBUG,
				   "RADIUS: Message removed from queue - restart from beginning");
			entry = radius->msgs;
			prev = NULL;
			continue;
		}

		s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
			radius->acct_sock;
		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
		    (s < 0 && entry->attempts > 0)) {
			if (entry->msg_type == RADIUS_ACCT ||
			    entry->msg_type == RADIUS_ACCT_INTERIM)
				acct_failover++;
			else
				auth_failover++;
		}

		if (first == 0 || entry->next_try < first)
			first = entry->next_try;

		prev = entry;
		entry = entry->next;
	}

	if (radius->msgs) {
		if (first < now.sec)
			first = now.sec;
		eloop_register_timeout(first - now.sec, 0,
				       radius_client_timer, radius, NULL);
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
			       "retransmit in %ld seconds",
			       (long int) (first - now.sec));
	}

	if (auth_failover)
		radius_client_auth_failover(radius);

	if (acct_failover)
		radius_client_acct_failover(radius);
}
示例#24
0
void hostapd_acs_channel_selected(struct hostapd_data *hapd,
				  struct acs_selected_channels *acs_res)
{
	int ret, i;
	int err = 0;

	if (hapd->iconf->channel) {
		wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
			   hapd->iconf->channel);
		return;
	}

	if (!hapd->iface->current_mode) {
		for (i = 0; i < hapd->iface->num_hw_features; i++) {
			struct hostapd_hw_modes *mode =
				&hapd->iface->hw_features[i];

			if (mode->mode == acs_res->hw_mode) {
				hapd->iface->current_mode = mode;
				break;
			}
		}
		if (!hapd->iface->current_mode) {
			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
				       HOSTAPD_LEVEL_WARNING,
				       "driver selected to bad hw_mode");
			err = 1;
			goto out;
		}
	}

	hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);

	if (!acs_res->pri_channel) {
		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING,
			       "driver switched to bad channel");
		err = 1;
		goto out;
	}

	hapd->iconf->channel = acs_res->pri_channel;
	hapd->iconf->acs = 1;

	if (acs_res->sec_channel == 0)
		hapd->iconf->secondary_channel = 0;
	else if (acs_res->sec_channel < acs_res->pri_channel)
		hapd->iconf->secondary_channel = -1;
	else if (acs_res->sec_channel > acs_res->pri_channel)
		hapd->iconf->secondary_channel = 1;
	else {
		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
		err = 1;
		goto out;
	}

	if (hapd->iface->conf->ieee80211ac) {
		/* set defaults for backwards compatibility */
		hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
		hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
		hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
		if (acs_res->ch_width == 80) {
			hapd->iconf->vht_oper_centr_freq_seg0_idx =
				acs_res->vht_seg0_center_ch;
			hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
		} else if (acs_res->ch_width == 160) {
			if (acs_res->vht_seg1_center_ch == 0) {
				hapd->iconf->vht_oper_centr_freq_seg0_idx =
					acs_res->vht_seg0_center_ch;
				hapd->iconf->vht_oper_chwidth =
					VHT_CHANWIDTH_160MHZ;
			} else {
				hapd->iconf->vht_oper_centr_freq_seg0_idx =
					acs_res->vht_seg0_center_ch;
				hapd->iconf->vht_oper_centr_freq_seg1_idx =
					acs_res->vht_seg1_center_ch;
				hapd->iconf->vht_oper_chwidth =
					VHT_CHANWIDTH_80P80MHZ;
			}
		}
	}

out:
	ret = hostapd_acs_completed(hapd->iface, err);
	if (ret) {
		wpa_printf(MSG_ERROR,
			   "ACS: Possibly channel configuration is invalid");
	}
}
示例#25
0
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
	struct radius_client_data *radius = eloop_ctx;
	struct hostapd_radius_servers *conf = radius->conf;
	RadiusType msg_type = (RadiusType) sock_ctx;
	int len, roundtrip;
	unsigned char buf[3000];
	struct radius_msg *msg;
	struct radius_hdr *hdr;
	struct radius_rx_handler *handlers;
	size_t num_handlers, i;
	struct radius_msg_list *req, *prev_req;
	struct os_reltime now;
	struct hostapd_radius_server *rconf;
	int invalid_authenticator = 0;

	if (msg_type == RADIUS_ACCT) {
		handlers = radius->acct_handlers;
		num_handlers = radius->num_acct_handlers;
		rconf = conf->acct_server;
	} else {
		handlers = radius->auth_handlers;
		num_handlers = radius->num_auth_handlers;
		rconf = conf->auth_server;
	}

	len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
	if (len < 0) {
		wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
		return;
	}
	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
		       "server", len);
	if (len == sizeof(buf)) {
		wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
		return;
	}

	msg = radius_msg_parse(buf, len);
	if (msg == NULL) {
		wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
		rconf->malformed_responses++;
		return;
	}
	hdr = radius_msg_get_hdr(msg);

	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
	if (conf->msg_dumps)
		radius_msg_dump(msg);

	switch (hdr->code) {
	case RADIUS_CODE_ACCESS_ACCEPT:
		rconf->access_accepts++;
		break;
	case RADIUS_CODE_ACCESS_REJECT:
		rconf->access_rejects++;
		break;
	case RADIUS_CODE_ACCESS_CHALLENGE:
		rconf->access_challenges++;
		break;
	case RADIUS_CODE_ACCOUNTING_RESPONSE:
		rconf->responses++;
		break;
	}

	prev_req = NULL;
	req = radius->msgs;
	while (req) {
		/* TODO: also match by src addr:port of the packet when using
		 * alternative RADIUS servers (?) */
		if ((req->msg_type == msg_type ||
		     (req->msg_type == RADIUS_ACCT_INTERIM &&
		      msg_type == RADIUS_ACCT)) &&
		    radius_msg_get_hdr(req->msg)->identifier ==
		    hdr->identifier)
			break;

		prev_req = req;
		req = req->next;
	}

	if (req == NULL) {
		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
			       HOSTAPD_LEVEL_DEBUG,
			       "No matching RADIUS request found (type=%d "
			       "id=%d) - dropping packet",
			       msg_type, hdr->identifier);
		goto fail;
	}

	os_get_reltime(&now);
	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
		(now.usec - req->last_attempt.usec) / 10000;
	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG,
		       "Received RADIUS packet matched with a pending "
		       "request, round trip time %d.%02d sec",
		       roundtrip / 100, roundtrip % 100);
	rconf->round_trip_time = roundtrip;

	/* Remove ACKed RADIUS packet from retransmit list */
	if (prev_req)
		prev_req->next = req->next;
	else
		radius->msgs = req->next;
	radius->num_msgs--;

	for (i = 0; i < num_handlers; i++) {
		RadiusRxResult res;
		res = handlers[i].handler(msg, req->msg, req->shared_secret,
					  req->shared_secret_len,
					  handlers[i].data);
		switch (res) {
		case RADIUS_RX_PROCESSED:
			radius_msg_free(msg);
			/* continue */
		case RADIUS_RX_QUEUED:
			radius_client_msg_free(req);
			return;
		case RADIUS_RX_INVALID_AUTHENTICATOR:
			invalid_authenticator++;
			/* continue */
		case RADIUS_RX_UNKNOWN:
			/* continue with next handler */
			break;
		}
	}

	if (invalid_authenticator)
		rconf->bad_authenticators++;
	else
		rconf->unknown_types++;
	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
		       HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
		       "(type=%d code=%d id=%d)%s - dropping packet",
		       msg_type, hdr->code, hdr->identifier,
		       invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
		       "");
	radius_client_msg_free(req);

 fail:
	radius_msg_free(msg);
}
示例#26
0
/**
 * ap_handle_timer - Per STA timer handler
 * @eloop_ctx: struct hostapd_data *
 * @timeout_ctx: struct sta_info *
 *
 * This function is called to check station activity and to remove inactive
 * stations.
 */
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
{
	struct hostapd_data *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;
		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
		if (inactive_sec == -1) {
			wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not "
				"get station info rom kernel driver for "
				MACSTR, MAC2STR(sta->addr));
		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
			   sta->flags & WLAN_STA_ASSOC) {
			/* station activity detected; reset timeout state */
			wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
				"active %is ago",
				MAC2STR(sta->addr), inactive_sec);
			sta->timeout_next = STA_NULLFUNC;
			next_time = hapd->conf->ap_max_inactivity -
				inactive_sec;
		} else {
			wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
				"inactive too long: %d sec, max allowed: %d",
				MAC2STR(sta->addr), inactive_sec,
				hapd->conf->ap_max_inactivity);
		}
	}

	if ((sta->flags & WLAN_STA_ASSOC) &&
	    sta->timeout_next == STA_DISASSOC &&
	    !(sta->flags & WLAN_STA_PENDING_POLL)) {
		wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data "
			"poll", MAC2STR(sta->addr));
		/* data nullfunc frame poll did not produce TX errors; assume
		 * station ACKed it */
		sta->timeout_next = STA_NULLFUNC;
		next_time = hapd->conf->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)) {
#ifndef CONFIG_NATIVE_WINDOWS
		/* send data frame to poll STA and check whether this frame
		 * is ACKed */
		struct {
			struct ieee80211_hdr hdr;
			u16 qos_ctl;
		} STRUCT_PACKED nulldata;
		int size = sizeof(struct ieee80211_hdr);

		wpa_printf(MSG_DEBUG, "  Polling STA with data frame");
		sta->flags |= WLAN_STA_PENDING_POLL;

		os_memset(&nulldata, 0, sizeof(nulldata));
		if (hapd->driver &&
		    os_strcmp(hapd->driver->name, "hostap") == 0) {
			/*
			 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
			 * but it is apparently not retried so TX Exc events
			 * are not received for it.
			 */
			nulldata.hdr.frame_control =
				IEEE80211_FC(WLAN_FC_TYPE_DATA,
					     WLAN_FC_STYPE_DATA);
		} else {
			if (sta->flags & WLAN_STA_WMM) {
				nulldata.hdr.frame_control =
					IEEE80211_FC(WLAN_FC_TYPE_DATA,
						     WLAN_FC_STYPE_QOS_NULL);
				size = sizeof(nulldata);
			} else
				nulldata.hdr.frame_control =
					IEEE80211_FC(WLAN_FC_TYPE_DATA,
						     WLAN_FC_STYPE_NULLFUNC);
		}

		nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
		os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, sta->addr,
			  ETH_ALEN);
		os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
			  ETH_ALEN);
		os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, hapd->own_addr,
			  ETH_ALEN);

		if (hostapd_drv_send_mlme(hapd, &nulldata, size) < 0)
			perror("ap_handle_timer: send");
#endif /* CONFIG_NATIVE_WINDOWS */
	} else if (sta->timeout_next != STA_REMOVE) {
		int deauth = sta->timeout_next == STA_DEAUTH;

		wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
			   deauth ? "deauthentication" : "disassociation",
			   MAC2STR(sta->addr));

		if (deauth) {
			hostapd_drv_sta_deauth(
				hapd, sta->addr,
				WLAN_REASON_PREV_AUTH_NOT_VALID);
		} else {
			hostapd_drv_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_notify_port_enabled(sta->eapol_sm, 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);
		mlme_disassociate_indication(
			hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
		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;
		mlme_deauthenticate_indication(
			hapd, sta,
			WLAN_REASON_PREV_AUTH_NOT_VALID);
		ap_free_sta(hapd, sta);
		break;
	}
}
示例#27
0
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
	struct hostapd_data *hapd = iface->bss[0];
	int i, j;
	u16 num_modes, flags;
	struct hostapd_hw_modes *modes;

	if (hostapd_drv_none(hapd))
		return -1;
	modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
	if (modes == NULL) {
		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_DEBUG,
			       "Fetching hardware channel/rate support not "
			       "supported.");
		return -1;
	}

	iface->hw_flags = flags;

	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
	iface->hw_features = modes;
	iface->num_hw_features = num_modes;

	for (i = 0; i < num_modes; i++) {
		struct hostapd_hw_modes *feature = &modes[i];
		int dfs_enabled = hapd->iconf->ieee80211h &&
			(iface->drv_flags & WPA_DRIVER_FLAGS_RADAR);

		/* set flag for channels we can use in current regulatory
		 * domain */
		for (j = 0; j < feature->num_channels; j++) {
			int dfs = 0;

			/*
			 * Disable all channels that are marked not to allow
			 * to initiate radiation (a.k.a. passive scan and no
			 * IBSS).
			 * Use radar channels only if the driver supports DFS.
			 */
			if ((feature->channels[j].flag &
			     HOSTAPD_CHAN_RADAR) && dfs_enabled) {
				dfs = 1;
			} else if (((feature->channels[j].flag &
				     HOSTAPD_CHAN_RADAR) &&
				    !(iface->drv_flags &
				      WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
				   (feature->channels[j].flag &
				    HOSTAPD_CHAN_NO_IR)) {
				feature->channels[j].flag |=
					HOSTAPD_CHAN_DISABLED;
			}

			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
				continue;

			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
				   "chan=%d freq=%d MHz max_tx_power=%d dBm%s",
				   feature->mode,
				   feature->channels[j].chan,
				   feature->channels[j].freq,
				   feature->channels[j].max_tx_power,
				   dfs ? dfs_info(&feature->channels[j]) : "");
		}
	}

	return 0;
}
示例#28
0
static int test_driver_new_sta(struct test_driver_data *drv,
			       struct test_driver_bss *bss, const u8 *addr,
			       const u8 *ie, size_t ielen)
{
	struct hostapd_data *hapd;
	struct sta_info *sta;
	int new_assoc, res;

	hapd = test_driver_get_hapd(drv, bss);
	if (hapd == NULL)
		return -1;

	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
		HOSTAPD_LEVEL_INFO, "associated");

	sta = ap_get_sta(hapd, addr);
	if (sta) {
		accounting_sta_stop(hapd, sta);
	} else {
		sta = ap_sta_add(hapd, addr);
		if (sta == NULL)
			return -1;
	}
	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);

	if (hapd->conf->wpa) {
		if (ie == NULL || ielen == 0) {
			if (hapd->conf->wps_state) {
				sta->flags |= WLAN_STA_WPS;
				goto skip_wpa_check;
			}

			printf("test_driver: no IE from STA\n");
			return -1;
		}
		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
			sta->flags |= WLAN_STA_WPS;
			goto skip_wpa_check;
		}

		if (sta->wpa_sm == NULL)
			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
							sta->addr);
		if (sta->wpa_sm == NULL) {
			printf("test_driver: Failed to initialize WPA state "
			       "machine\n");
			return -1;
		}
		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
					  ie, ielen, NULL, 0);
		if (res != WPA_IE_OK) {
			printf("WPA/RSN information element rejected? "
			       "(res %u)\n", res);
			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
			return -1;
		}
	}
skip_wpa_check:

	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
	wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);

	hostapd_new_assoc_sta(hapd, sta, !new_assoc);

	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);

	return 0;
}
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
			     int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
	int channel, chwidth, seg0_idx = 0, seg1_idx = 0;

	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
		       "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
		       freq, ht, offset, width, cf1, cf2);

	hapd->iface->freq = freq;

	channel = hostapd_hw_get_channel(hapd, freq);
	if (!channel) {
		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
			       HOSTAPD_LEVEL_WARNING, "driver switched to "
			       "bad channel!");
		return;
	}

	switch (width) {
	case CHAN_WIDTH_80:
		chwidth = VHT_CHANWIDTH_80MHZ;
		break;
	case CHAN_WIDTH_80P80:
		chwidth = VHT_CHANWIDTH_80P80MHZ;
		break;
	case CHAN_WIDTH_160:
		chwidth = VHT_CHANWIDTH_160MHZ;
		break;
	case CHAN_WIDTH_20_NOHT:
	case CHAN_WIDTH_20:
	case CHAN_WIDTH_40:
	default:
		chwidth = VHT_CHANWIDTH_USE_HT;
		break;
	}

	switch (hapd->iface->current_mode->mode) {
	case HOSTAPD_MODE_IEEE80211A:
		if (cf1 > 5000)
			seg0_idx = (cf1 - 5000) / 5;
		if (cf2 > 5000)
			seg1_idx = (cf2 - 5000) / 5;
		break;
	default:
		seg0_idx = hostapd_hw_get_channel(hapd, cf1);
		seg1_idx = hostapd_hw_get_channel(hapd, cf2);
		break;
	}

	hapd->iconf->channel = channel;
	hapd->iconf->ieee80211n = ht;
	hapd->iconf->secondary_channel = offset;
	hapd->iconf->vht_oper_chwidth = chwidth;
	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
	hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;

	if (hapd->csa_in_progress &&
	    freq == hapd->cs_freq_params.freq) {
		hostapd_cleanup_cs_params(hapd);
		ieee802_11_set_beacon(hapd);

		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
			freq);
	}
#endif /* NEED_AP_MLME */
}
示例#30
0
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
			const u8 *req_ies, size_t req_ies_len, int reassoc)
{
	struct sta_info *sta;
	int new_assoc, res;
	struct ieee802_11_elems elems;
	const u8 *ie;
	size_t ielen;
#ifdef CONFIG_IEEE80211R
	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
	u8 *p = buf;
	size_t len = 0;
#endif /* CONFIG_IEEE80211R */
	int resp = WLAN_STATUS_SUCCESS;

	if (addr == NULL) {
		/*
		 * This could potentially happen with unexpected event from the
		 * driver wrapper. This was seen at least in one case where the
		 * driver ended up being set to station mode while hostapd was
		 * running, so better make sure we stop processing such an
		 * event here.
		 */
		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
			   "no address");
		return -1;
	}
	random_add_randomness(addr, ETH_ALEN);

	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
		       HOSTAPD_LEVEL_INFO, "associated");

	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
	if (elems.wps_ie) {
		ie = elems.wps_ie - 2;
		ielen = elems.wps_ie_len + 2;
		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
	} else if (elems.rsn_ie) {
		ie = elems.rsn_ie - 2;
		ielen = elems.rsn_ie_len + 2;
		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
	} else if (elems.wpa_ie) {
		ie = elems.wpa_ie - 2;
		ielen = elems.wpa_ie_len + 2;
		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
	} else {
		ie = NULL;
		ielen = 0;
		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
			   "(Re)AssocReq");
	}

	sta = ap_get_sta(hapd, addr);
	if (sta) {
		accounting_sta_stop(hapd, sta);
	} else {
		sta = ap_sta_add(hapd, addr);
		if (sta == NULL)
			return -1;
	}
	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);

#ifdef CONFIG_P2P
	if (elems.p2p) {
		wpabuf_free(sta->p2p_ie);
		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
							  P2P_IE_VENDOR_TYPE);
	}
#endif /* CONFIG_P2P */

	if (hapd->conf->wpa) {
		if (ie == NULL || ielen == 0) {
			if (hapd->conf->wps_state) {
				wpa_printf(MSG_DEBUG, "STA did not include "
					   "WPA/RSN IE in (Re)Association "
					   "Request - possible WPS use");
				sta->flags |= WLAN_STA_MAYBE_WPS;
				goto skip_wpa_check;
			}

			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
			return -1;
		}
		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
			struct wpabuf *wps;
			sta->flags |= WLAN_STA_WPS;
			wps = ieee802_11_vendor_ie_concat(ie, ielen,
                                                         WPS_IE_VENDOR_TYPE);
			if (wps) {
                        	if (wps_is_20(wps)) {
					wpa_printf(MSG_DEBUG, "WPS: STA "
                                                  "supports WPS 2.0");
					sta->flags |= WLAN_STA_WPS2;
				}
				wpabuf_free(wps);
			}
			goto skip_wpa_check;
		}

		if (sta->wpa_sm == NULL)
			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
							sta->addr);
		if (sta->wpa_sm == NULL) {
			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
				   "machine");
			return -1;
		}
		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
					  ie, ielen,
					  elems.mdie, elems.mdie_len);
		if (res != WPA_IE_OK) {
			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
				   "rejected? (res %u)", res);
			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
			if (res == WPA_INVALID_GROUP)
				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
			else if (res == WPA_INVALID_PAIRWISE)
				resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
			else if (res == WPA_INVALID_AKMP)
				resp = WLAN_REASON_AKMP_NOT_VALID;
#ifdef CONFIG_IEEE80211W
			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
				resp = WLAN_REASON_INVALID_IE;
			else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
#endif /* CONFIG_IEEE80211W */
			else
				resp = WLAN_REASON_INVALID_IE;
			goto fail;
		}
#ifdef CONFIG_IEEE80211R
		if (sta->auth_alg == WLAN_AUTH_FT) {
			resp = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
						       req_ies_len);
			if (resp != WLAN_STATUS_SUCCESS)
				goto fail;
		}
#endif /* CONFIG_IEEE80211R */
	} else if (hapd->conf->wps_state) {
			struct wpabuf *wps;
			wps = ieee802_11_vendor_ie_concat(ie, ielen,
							  WPS_IE_VENDOR_TYPE);
#ifdef CONFIG_WPS_STRICT
		if (ie) {
			if (wps && wps_validate_assoc_req(wps) < 0) {
				resp = WLAN_REASON_INVALID_IE;
				wpabuf_free(wps);
				goto fail;
			}
		}
#endif /* CONFIG_WPS_STRICT */
		if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
			sta->flags |= WLAN_STA_WPS;
			if (wps && wps_is_20(wps)) {
				wpa_printf(MSG_DEBUG, "WPS: STA supports "
					    "WPS 2.0");
				sta->flags |= WLAN_STA_WPS2;
			}
		} else
			sta->flags |= WLAN_STA_MAYBE_WPS;
			wpabuf_free(wps);
	}
skip_wpa_check:

#ifdef CONFIG_IEEE80211R
	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
					sta->auth_alg, req_ies, req_ies_len);
	len = p - buf;

	hostapd_sta_assoc(hapd, addr, reassoc, 0, buf, len);
#endif /* CONFIG_IEEE80211R */

	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;

	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
	else
		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);

	hostapd_new_assoc_sta(hapd, sta, !new_assoc);

	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);

#ifdef CONFIG_P2P
	p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
			      req_ies, req_ies_len);
#endif /* CONFIG_P2P */

	return 0;

fail:
#ifdef CONFIG_IEEE80211R
	hostapd_sta_assoc(hapd, addr, reassoc, resp, buf, len);
#endif /* CONFIG_IEEE80211R */
	hostapd_drv_sta_disassoc(hapd, sta->addr, resp);
	ap_free_sta(hapd, sta);
	return -1;
}