Exemple #1
0
static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
{
	struct wpabuf *extra_ie = NULL;
#ifdef CONFIG_WPS
	int wps = 0;
	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */

#ifdef CONFIG_INTERWORKING
	if (wpa_s->conf->interworking &&
	    wpabuf_resize(&extra_ie, 100) == 0)
		wpas_add_interworking_elements(wpa_s, extra_ie);
#endif /* CONFIG_INTERWORKING */

#ifdef CONFIG_WPS
	wps = wpas_wps_in_use(wpa_s, &req_type);

	if (wps) {
		struct wpabuf *wps_ie;
		wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
						DEV_PW_DEFAULT,
						&wpa_s->wps->dev,
						wpa_s->wps->uuid, req_type,
						0, NULL);
		if (wps_ie) {
			if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
				wpabuf_put_buf(extra_ie, wps_ie);
			wpabuf_free(wps_ie);
		}
	}

#ifdef CONFIG_P2P
	if (wps) {
		size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
		if (wpabuf_resize(&extra_ie, ielen) == 0)
			wpas_p2p_scan_ie(wpa_s, extra_ie);
	}
#endif /* CONFIG_P2P */

#endif /* CONFIG_WPS */

#ifdef CONFIG_HS20
	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
		wpas_hs20_add_indication(extra_ie);
#endif /* CONFIG_HS20 */

	return extra_ie;
}
static int eap_fast_encrypt_phase2(struct eap_sm *sm,
				   struct eap_fast_data *data,
				   struct wpabuf *plain, int piggyback)
{
	struct wpabuf *encr;

	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
			    plain);
	encr = eap_server_tls_encrypt(sm, &data->ssl, plain);
	wpabuf_free(plain);

	if (data->ssl.tls_out && piggyback) {
		wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
			   "(len=%d) with last Phase 1 Message (len=%d "
			   "used=%d)",
			   (int) wpabuf_len(encr),
			   (int) wpabuf_len(data->ssl.tls_out),
			   (int) data->ssl.tls_out_pos);
		if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(encr)) < 0) {
			wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize "
				   "output buffer");
			wpabuf_free(encr);
			return -1;
		}
		wpabuf_put_buf(data->ssl.tls_out, encr);
		wpabuf_free(encr);
	} else {
		wpabuf_free(data->ssl.tls_out);
		data->ssl.tls_out_pos = 0;
		data->ssl.tls_out = encr;
	}

	return 0;
}
Exemple #3
0
u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
		     const u8 *data, size_t len)
{
	int attr_len = 4 + len;
	int pad_len;
	u8 *start;

	if (msg == NULL)
		return NULL;

	pad_len = (4 - attr_len % 4) % 4;
	attr_len += pad_len;
	if (wpabuf_resize(&msg->buf, attr_len))
		return NULL;
	start = wpabuf_put(msg->buf, 0);
	wpabuf_put_u8(msg->buf, attr);
	wpabuf_put_u8(msg->buf, attr_len / 4);
	wpabuf_put_be16(msg->buf, value);
	if (data)
		wpabuf_put_data(msg->buf, data, len);
	else
		wpabuf_put(msg->buf, len);
	if (pad_len)
		os_memset(wpabuf_put(msg->buf, pad_len), 0, pad_len);
	return start;
}
Exemple #4
0
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
					    const u8 *data, size_t data_len)
{
	size_t buf_needed;
	struct radius_attr_hdr *attr;

	if (data_len > RADIUS_MAX_ATTR_LEN) {
		printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
		       (unsigned long) data_len);
		return NULL;
	}

	buf_needed = sizeof(*attr) + data_len;

	if (wpabuf_tailroom(msg->buf) < buf_needed) {
		/* allocate more space for message buffer */
		if (wpabuf_resize(&msg->buf, buf_needed) < 0)
			return NULL;
		msg->hdr = wpabuf_mhead(msg->buf);
	}

	attr = wpabuf_put(msg->buf, sizeof(struct radius_attr_hdr));
	attr->type = type;
	attr->length = sizeof(*attr) + data_len;
	wpabuf_put_data(msg->buf, data, data_len);

	if (radius_msg_add_attr_to_array(msg, attr))
		return NULL;

	return attr;
}
static int add_buf_data(struct wpabuf **dst, const u8 *data, size_t len)
{
	if (!data || !len)
		return 0;
	if (wpabuf_resize(dst, len) != 0)
		return -1;
	wpabuf_put_data(*dst, data, len);
	return 0;
}
static int add_buf(struct wpabuf **dst, const struct wpabuf *src)
{
	if (!src)
		return 0;
	if (wpabuf_resize(dst, wpabuf_len(src)) != 0)
		return -1;
	wpabuf_put_buf(*dst, src);
	return 0;
}
static int eap_peapv2_start_phase2(struct eap_sm *sm,
				   struct eap_peap_data *data)
{
	struct wpabuf *buf, *buf2;
	int res;

	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
		   "payload in the same message");
	eap_peap_state(data, PHASE1_ID2);
	if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY))
		return -1;

	/* TODO: which Id to use here? */
	buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6);
	if (buf == NULL)
		return -1;

	buf2 = eap_peapv2_tlv_eap_payload(buf);
	if (buf2 == NULL)
		return -1;

	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2);

	buf = wpabuf_alloc(data->ssl.tls_out_limit);
	if (buf == NULL) {
		wpabuf_free(buf2);
		return -1;
	}

	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
				     wpabuf_head(buf2), wpabuf_len(buf2),
				     wpabuf_put(buf, 0),
				     data->ssl.tls_out_limit);
	wpabuf_free(buf2);

	if (res < 0) {
		wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 "
			   "data");
		wpabuf_free(buf);
		return -1;
	}

	wpabuf_put(buf, res);
	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request",
			buf);

	/* Append TLS data into the pending buffer after the Server Finished */
	if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) {
		wpabuf_free(buf);
		return -1;
	}
	wpabuf_put_buf(data->ssl.out_buf, buf);
	wpabuf_free(buf);

	return 0;
}
Exemple #8
0
/**
 * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
 * @data: Data for TLS processing
 * @in_data: Next incoming TLS segment
 * Returns: 0 on success, 1 if more data is needed for the full message, or
 * -1 on error
 */
static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
					    const struct wpabuf *in_data)
{
	size_t tls_in_len, in_len;

	tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
	in_len = in_data ? wpabuf_len(in_data) : 0;

	if (tls_in_len + in_len == 0) {
		/* No message data received?! */
		wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
			   "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
			   (unsigned long) data->tls_in_left,
			   (unsigned long) tls_in_len,
			   (unsigned long) in_len);
		eap_peer_tls_reset_input(data);
		return -1;
	}

	if (tls_in_len + in_len > 65536) {
		/*
		 * Limit length to avoid rogue servers from causing large
		 * memory allocations.
		 */
		wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
			   "64 kB)");
		eap_peer_tls_reset_input(data);
		return -1;
	}

	if (in_len > data->tls_in_left) {
		/* Sender is doing something odd - reject message */
		wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
			   "indicated");
		eap_peer_tls_reset_input(data);
		return -1;
	}

	if (wpabuf_resize(&data->tls_in, in_len) < 0) {
		wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
			   "data");
		eap_peer_tls_reset_input(data);
		return -1;
	}
	if (in_data)
		wpabuf_put_buf(data->tls_in, in_data);
	data->tls_in_left -= in_len;

	if (data->tls_in_left > 0) {
		wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
			   "data", (unsigned long) data->tls_in_left);
		return 1;
	}

	return 0;
}
Exemple #9
0
static int gas_query_append(struct gas_query_pending *query, const u8 *data,
			    size_t len)
{
	if (wpabuf_resize(&query->resp, len) < 0) {
		wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
		return -1;
	}
	wpabuf_put_data(query->resp, data, len);
	return 0;
}
Exemple #10
0
void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
				     struct wpabuf **extra_ie)
{
	/* EID + 0-length (wildcard) mesh-id */
	size_t ielen = 2;

	if (wpabuf_resize(extra_ie, ielen) == 0) {
		wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
		wpabuf_put_u8(*extra_ie, 0);
	}
}
static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
			     size_t len)
{
	struct tls_connection *conn = (struct tls_connection *) ptr;

	if (wpabuf_resize(&conn->push_buf, len) < 0) {
		errno = ENOMEM;
		return -1;
	}
	wpabuf_put_data(conn->push_buf, buf, len);

	return len;
}
Exemple #12
0
static int eap_aka_add_id_msg(struct eap_aka_data *data,
                              const struct wpabuf *msg)
{
    if (msg == NULL)
        return -1;

    if (data->id_msgs == NULL) {
        data->id_msgs = wpabuf_dup(msg);
        return data->id_msgs == NULL ? -1 : 0;
    }

    if (wpabuf_resize(&data->id_msgs, wpabuf_len(msg)) < 0)
        return -1;
    wpabuf_put_buf(data->id_msgs, msg);

    return 0;
}
static struct wpabuf * eap_eke_build_commit(struct eap_sm *sm,
					    struct eap_eke_data *data, u8 id)
{
	struct wpabuf *msg;
	u8 pub[EAP_EKE_MAX_DH_LEN];

	wpa_printf(MSG_DEBUG, "EAP-EKE: Request/Commit");

	if (sm->user == NULL || sm->user->password == NULL) {
		wpa_printf(MSG_INFO, "EAP-EKE: Password with not configured");
		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
		return eap_eke_build_failure(data, id);
	}

	if (eap_eke_derive_key(&data->sess, sm->user->password,
			       sm->user->password_len,
			       sm->server_id, sm->server_id_len,
			       data->peerid, data->peerid_len, data->key) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return eap_eke_build_failure(data, id);
	}

	msg = eap_eke_build_msg(data, id, data->sess.dhcomp_len,
				EAP_EKE_COMMIT);
	if (msg == NULL) {
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return eap_eke_build_failure(data, id);
	}

	/*
	 * y_s = g ^ x_s (mod p)
	 * x_s = random number 2 .. p-1
	 * temp = prf(0+, password)
	 * key = prf+(temp, ID_S | ID_P)
	 * DHComponent_S = Encr(key, y_s)
	 */

	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return eap_eke_build_failure(data, id);
	}

	if (eap_eke_dhcomp(&data->sess, data->key, pub,
			   wpabuf_put(msg, data->sess.dhcomp_len))
	    < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
		wpabuf_free(msg);
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return eap_eke_build_failure(data, id);
	}

	if (wpabuf_resize(&data->msgs, wpabuf_len(msg)) < 0) {
		wpabuf_free(msg);
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return eap_eke_build_failure(data, id);
	}
	wpabuf_put_buf(data->msgs, msg);

	return msg;
}
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
			       struct wpabuf **beacon_ret,
			       struct wpabuf **proberesp_ret,
			       struct wpabuf **assocresp_ret)
{
	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
	u8 buf[200], *pos;

	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;

	pos = buf;
	pos = hostapd_eid_time_adv(hapd, pos);
	if (add_buf_data(&beacon, buf, pos - buf) < 0)
		goto fail;
	pos = hostapd_eid_time_zone(hapd, pos);
	if (add_buf_data(&proberesp, buf, pos - buf) < 0)
		goto fail;

	pos = buf;
	pos = hostapd_eid_ext_capab(hapd, pos);
	if (add_buf_data(&assocresp, buf, pos - buf) < 0)
		goto fail;
	pos = hostapd_eid_interworking(hapd, pos);
	pos = hostapd_eid_adv_proto(hapd, pos);
	pos = hostapd_eid_roaming_consortium(hapd, pos);
	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
	    add_buf_data(&proberesp, buf, pos - buf) < 0)
		goto fail;

#ifdef CONFIG_FST
	if (add_buf(&beacon, hapd->iface->fst_ies) < 0 ||
	    add_buf(&proberesp, hapd->iface->fst_ies) < 0 ||
	    add_buf(&assocresp, hapd->iface->fst_ies) < 0)
		goto fail;
#endif /* CONFIG_FST */

#ifdef CONFIG_FILS
	pos = hostapd_eid_fils_indic(hapd, buf, 0);
	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
	    add_buf_data(&proberesp, buf, pos - buf) < 0)
		goto fail;
#endif /* CONFIG_FILS */

	if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
	    add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
		goto fail;

#ifdef CONFIG_P2P
	if (add_buf(&beacon, hapd->p2p_beacon_ie) < 0 ||
	    add_buf(&proberesp, hapd->p2p_probe_resp_ie) < 0)
		goto fail;
#endif /* CONFIG_P2P */

#ifdef CONFIG_P2P_MANAGER
	if (hapd->conf->p2p & P2P_MANAGE) {
		if (wpabuf_resize(&beacon, 100) == 0) {
			u8 *start, *p;
			start = wpabuf_put(beacon, 0);
			p = hostapd_eid_p2p_manage(hapd, start);
			wpabuf_put(beacon, p - start);
		}

		if (wpabuf_resize(&proberesp, 100) == 0) {
			u8 *start, *p;
			start = wpabuf_put(proberesp, 0);
			p = hostapd_eid_p2p_manage(hapd, start);
			wpabuf_put(proberesp, p - start);
		}
	}
#endif /* CONFIG_P2P_MANAGER */

#ifdef CONFIG_WPS
	if (hapd->conf->wps_state) {
		struct wpabuf *a = wps_build_assoc_resp_ie();
		add_buf(&assocresp, a);
		wpabuf_free(a);
	}
#endif /* CONFIG_WPS */

#ifdef CONFIG_P2P_MANAGER
	if (hapd->conf->p2p & P2P_MANAGE) {
		if (wpabuf_resize(&assocresp, 100) == 0) {
			u8 *start, *p;
			start = wpabuf_put(assocresp, 0);
			p = hostapd_eid_p2p_manage(hapd, start);
			wpabuf_put(assocresp, p - start);
		}
	}
#endif /* CONFIG_P2P_MANAGER */

#ifdef CONFIG_WIFI_DISPLAY
	if (hapd->p2p_group) {
		struct wpabuf *a;
		a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
		add_buf(&assocresp, a);
		wpabuf_free(a);
	}
#endif /* CONFIG_WIFI_DISPLAY */

#ifdef CONFIG_HS20
	pos = hostapd_eid_hs20_indication(hapd, buf);
	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
	    add_buf_data(&proberesp, buf, pos - buf) < 0)
		goto fail;

	pos = hostapd_eid_osen(hapd, buf);
	if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
	    add_buf_data(&proberesp, buf, pos - buf) < 0)
		goto fail;
#endif /* CONFIG_HS20 */

#ifdef CONFIG_MBO
	if (hapd->conf->mbo_enabled || hapd->enable_oce) {
		pos = hostapd_eid_mbo(hapd, buf, sizeof(buf));
		if (add_buf_data(&beacon, buf, pos - buf) < 0 ||
		    add_buf_data(&proberesp, buf, pos - buf) < 0 ||
		    add_buf_data(&assocresp, buf, pos - buf) < 0)
			goto fail;
	}
#endif /* CONFIG_MBO */

	add_buf(&beacon, hapd->conf->vendor_elements);
	add_buf(&proberesp, hapd->conf->vendor_elements);
	add_buf(&assocresp, hapd->conf->assocresp_elements);

	*beacon_ret = beacon;
	*proberesp_ret = proberesp;
	*assocresp_ret = assocresp;

	return 0;

fail:
	wpabuf_free(beacon);
	wpabuf_free(proberesp);
	wpabuf_free(assocresp);
	return -1;
}
Exemple #15
0
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
	struct wpa_supplicant *wpa_s = eloop_ctx;
	struct wpa_ssid *ssid;
	enum scan_req_type scan_req = NORMAL_SCAN_REQ;
	int ret;
	struct wpabuf *extra_ie = NULL;
	struct wpa_driver_scan_params params;
	struct wpa_driver_scan_params *scan_params;
	size_t max_ssids;
	enum wpa_states prev_state;

	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
		return;
	}

	if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
		return;
	}

	if (!wpa_supplicant_enabled_networks(wpa_s) &&
	    wpa_s->scan_req == NORMAL_SCAN_REQ) {
		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
#ifdef CONFIG_P2P
		wpa_s->sta_scan_pending = 0;
#endif /* CONFIG_P2P */
		return;
	}

	if (wpa_s->conf->ap_scan != 0 &&
	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
			"overriding ap_scan configuration");
		wpa_s->conf->ap_scan = 0;
		wpas_notify_ap_scan_changed(wpa_s);
	}

	if (wpa_s->conf->ap_scan == 0) {
		wpa_supplicant_gen_assoc_event(wpa_s);
		return;
	}

#ifdef CONFIG_P2P
	if (wpas_p2p_in_progress(wpa_s)) {
		if (wpa_s->sta_scan_pending &&
		    wpas_p2p_in_progress(wpa_s) == 2 &&
		    wpa_s->global->p2p_cb_on_scan_complete) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
				"mode scan during P2P search");
		} else {
			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
				"while P2P operation is in progress");
			wpa_s->sta_scan_pending = 1;
			wpa_supplicant_req_scan(wpa_s, 5, 0);
			return;
		}
	}
#endif /* CONFIG_P2P */

	if (wpa_s->conf->ap_scan == 2)
		max_ssids = 1;
	else {
		max_ssids = wpa_s->max_scan_ssids;
		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
			max_ssids = WPAS_MAX_SCAN_SSIDS;
	}

	scan_req = wpa_s->scan_req;
	wpa_s->scan_req = NORMAL_SCAN_REQ;

	os_memset(&params, 0, sizeof(params));

	prev_state = wpa_s->wpa_state;
	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
	    wpa_s->wpa_state == WPA_INACTIVE)
		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);

	/*
	 * If autoscan has set its own scanning parameters
	 */
	if (wpa_s->autoscan_params != NULL) {
		scan_params = wpa_s->autoscan_params;
		goto scan;
	}

	if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
			if (ssid == wpa_s->connect_without_scan)
				break;
		}
		wpa_s->connect_without_scan = NULL;
		if (ssid) {
			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
				   "without scan step");
			wpa_supplicant_associate(wpa_s, NULL, ssid);
			return;
		}
	}

#ifdef CONFIG_P2P
	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
	    wpa_s->go_params) {
		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
			   "P2P group formation");
		params.ssids[0].ssid = wpa_s->go_params->ssid;
		params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
		params.num_ssids = 1;
		goto ssid_list_set;
	}
#endif /* CONFIG_P2P */

	/* Find the starting point from which to continue scanning */
	ssid = wpa_s->conf->ssid;
	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
		while (ssid) {
			if (ssid == wpa_s->prev_scan_ssid) {
				ssid = ssid->next;
				break;
			}
			ssid = ssid->next;
		}
	}

	if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
		wpa_s->connect_without_scan = NULL;
		wpa_s->prev_scan_wildcard = 0;
		wpa_supplicant_assoc_try(wpa_s, ssid);
		return;
	} else if (wpa_s->conf->ap_scan == 2) {
		/*
		 * User-initiated scan request in ap_scan == 2; scan with
		 * wildcard SSID.
		 */
		ssid = NULL;
	} else {
		struct wpa_ssid *start = ssid, *tssid;
		int freqs_set = 0;
		if (ssid == NULL && max_ssids > 1)
			ssid = wpa_s->conf->ssid;
		while (ssid) {
			if (!wpas_network_disabled(wpa_s, ssid) &&
			    ssid->scan_ssid) {
				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
						  ssid->ssid, ssid->ssid_len);
				params.ssids[params.num_ssids].ssid =
					ssid->ssid;
				params.ssids[params.num_ssids].ssid_len =
					ssid->ssid_len;
				params.num_ssids++;
				if (params.num_ssids + 1 >= max_ssids)
					break;
			}
			ssid = ssid->next;
			if (ssid == start)
				break;
			if (ssid == NULL && max_ssids > 1 &&
			    start != wpa_s->conf->ssid)
				ssid = wpa_s->conf->ssid;
		}

		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
			if (wpas_network_disabled(wpa_s, tssid))
				continue;
			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
				int_array_concat(&params.freqs,
						 tssid->scan_freq);
			} else {
				os_free(params.freqs);
				params.freqs = NULL;
			}
			freqs_set = 1;
		}
		int_array_sort_unique(params.freqs);
	}

	if (ssid && max_ssids == 1) {
		/*
		 * If the driver is limited to 1 SSID at a time interleave
		 * wildcard SSID scans with specific SSID scans to avoid
		 * waiting a long time for a wildcard scan.
		 */
		if (!wpa_s->prev_scan_wildcard) {
			params.ssids[0].ssid = NULL;
			params.ssids[0].ssid_len = 0;
			wpa_s->prev_scan_wildcard = 1;
			wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
				"wildcard SSID (Interleave with specific)");
		} else {
			wpa_s->prev_scan_ssid = ssid;
			wpa_s->prev_scan_wildcard = 0;
			wpa_dbg(wpa_s, MSG_DEBUG,
				"Starting AP scan for specific SSID: %s",
				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
		}
	} else if (ssid) {
		/* max_ssids > 1 */

		wpa_s->prev_scan_ssid = ssid;
		wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
			"the scan request");
		params.num_ssids++;
	} else {
		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
		params.num_ssids++;
		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
			"SSID");
	}
#ifdef CONFIG_P2P
ssid_list_set:
#endif /* CONFIG_P2P */

	wpa_supplicant_optimize_freqs(wpa_s, &params);
	extra_ie = wpa_supplicant_extra_ies(wpa_s);

#ifdef CONFIG_HS20
	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 7) == 0)
		wpas_hs20_add_indication(extra_ie);
#endif /* CONFIG_HS20 */

	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
			"generated frequency list");
		params.freqs = wpa_s->next_scan_freqs;
	} else
		os_free(wpa_s->next_scan_freqs);
	wpa_s->next_scan_freqs = NULL;

	params.filter_ssids = wpa_supplicant_build_filter_ssids(
		wpa_s->conf, &params.num_filter_ssids);
	if (extra_ie) {
		params.extra_ies = wpabuf_head(extra_ie);
		params.extra_ies_len = wpabuf_len(extra_ie);
	}

#ifdef CONFIG_P2P
	if (wpa_s->p2p_in_provisioning ||
	    (wpa_s->show_group_started && wpa_s->go_params)) {
		/*
		 * The interface may not yet be in P2P mode, so we have to
		 * explicitly request P2P probe to disable CCK rates.
		 */
		params.p2p_probe = 1;
	}
#endif /* CONFIG_P2P */

	scan_params = &params;

scan:
#ifdef CONFIG_P2P
	/*
	 * If the driver does not support multi-channel concurrency and a
	 * virtual interface that shares the same radio with the wpa_s interface
	 * is operating there may not be need to scan other channels apart from
	 * the current operating channel on the other virtual interface. Filter
	 * out other channels in case we are trying to find a connection for a
	 * station interface when we are not configured to prefer station
	 * connection and a concurrent operation is already in process.
	 */
	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
	    !scan_params->freqs && !params.freqs &&
	    wpas_is_p2p_prioritized(wpa_s) &&
	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
	    non_p2p_network_enabled(wpa_s)) {
		int freq = shared_vif_oper_freq(wpa_s);
		if (freq > 0) {
			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
				"operating channel (%d MHz) since driver does "
				"not support multi-channel concurrency", freq);
			params.freqs = os_zalloc(sizeof(int) * 2);
			if (params.freqs)
				params.freqs[0] = freq;
			scan_params->freqs = params.freqs;
		}
	}
#endif /* CONFIG_P2P */

	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);

	wpabuf_free(extra_ie);
	os_free(params.freqs);
	os_free(params.filter_ssids);

	if (ret) {
		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
		if (prev_state != wpa_s->wpa_state)
			wpa_supplicant_set_state(wpa_s, prev_state);
		/* Restore scan_req since we will try to scan again */
		wpa_s->scan_req = scan_req;
		wpa_supplicant_req_scan(wpa_s, 1, 0);
	} else {
		wpa_s->scan_for_connection = 0;
	}
}
Exemple #16
0
static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm,
					      struct eap_eke_data *data,
					      struct eap_method_ret *ret,
					      const struct wpabuf *reqData,
					      const u8 *payload,
					      size_t payload_len)
{
	struct wpabuf *resp;
	const u8 *pos, *end, *dhcomp;
	size_t prot_len;
	u8 *rpos;
	u8 key[EAP_EKE_MAX_KEY_LEN];
	u8 pub[EAP_EKE_MAX_DH_LEN];
	const u8 *password;
	size_t password_len;
	u8 id = eap_get_id(reqData);

	if (data->state != COMMIT) {
		wpa_printf(MSG_DEBUG, "EAP-EKE: EAP-EKE-Commit/Request received in unexpected state (%d)", data->state);
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PROTO_ERROR);
	}

	wpa_printf(MSG_DEBUG, "EAP-EKE: Received EAP-EKE-Commit/Request");

	password = eap_get_config_password(sm, &password_len);
	if (password == NULL) {
		wpa_printf(MSG_INFO, "EAP-EKE: No password configured!");
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PASSWD_NOT_FOUND);
	}

	pos = payload;
	end = payload + payload_len;

	if (pos + data->sess.dhcomp_len > end) {
		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PROTO_ERROR);
	}

	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_S",
		    pos, data->sess.dhcomp_len);
	dhcomp = pos;
	pos += data->sess.dhcomp_len;
	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);

	/*
	 * temp = prf(0+, password)
	 * key = prf+(temp, ID_S | ID_P)
	 */
	if (eap_eke_derive_key(&data->sess, password, password_len,
			       data->serverid, data->serverid_len,
			       data->peerid, data->peerid_len, key) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive key");
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}

	/*
	 * y_p = g ^ x_p (mod p)
	 * x_p = random number 2 .. p-1
	 */
	if (eap_eke_dh_init(data->sess.dhgroup, data->dh_priv, pub) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to initialize DH");
		os_memset(key, 0, sizeof(key));
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}

	if (eap_eke_shared_secret(&data->sess, key, data->dh_priv, dhcomp) < 0)
	{
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
		os_memset(key, 0, sizeof(key));
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}

	if (eap_eke_derive_ke_ki(&data->sess,
				 data->serverid, data->serverid_len,
				 data->peerid, data->peerid_len) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
		os_memset(key, 0, sizeof(key));
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}

	wpa_printf(MSG_DEBUG, "EAP-EKE: Sending EAP-EKE-Commit/Response");

	resp = eap_eke_build_msg(data, id,
				 data->sess.dhcomp_len + data->sess.pnonce_len,
				 EAP_EKE_COMMIT);
	if (resp == NULL) {
		os_memset(key, 0, sizeof(key));
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}

	/* DHComponent_P = Encr(key, y_p) */
	rpos = wpabuf_put(resp, data->sess.dhcomp_len);
	if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
		wpabuf_free(resp);
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
		os_memset(key, 0, sizeof(key));
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}
	os_memset(key, 0, sizeof(key));

	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
		    rpos, data->sess.dhcomp_len);

	if (random_get_bytes(data->nonce_p, data->sess.nonce_len)) {
		wpabuf_free(resp);
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}
	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
			data->nonce_p, data->sess.nonce_len);
	prot_len = wpabuf_tailroom(resp);
	if (eap_eke_prot(&data->sess, data->nonce_p, data->sess.nonce_len,
			 wpabuf_put(resp, 0), &prot_len) < 0) {
		wpabuf_free(resp);
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}
	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P",
		    wpabuf_put(resp, 0), prot_len);
	wpabuf_put(resp, prot_len);

	/* TODO: CBValue */

	if (wpabuf_resize(&data->msgs, wpabuf_len(reqData) + wpabuf_len(resp))
	    < 0) {
		wpabuf_free(resp);
		return eap_eke_build_fail(data, ret, id,
					  EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
	}
	wpabuf_put_buf(data->msgs, reqData);
	wpabuf_put_buf(data->msgs, resp);

	eap_eke_state(data, CONFIRM);

	return resp;
}
Exemple #17
0
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
	struct wpa_supplicant *wpa_s = eloop_ctx;
	struct wpa_ssid *ssid;
	int scan_req = 0, ret;
	struct wpabuf *extra_ie;
	struct wpa_driver_scan_params params;
	size_t max_ssids;
	enum wpa_states prev_state;

	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
		return;
	}

	if (wpa_s->disconnected && !wpa_s->scan_req) {
		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
		return;
	}

	if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
	    !wpa_s->scan_req) {
		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
		return;
	}

	if (wpa_s->conf->ap_scan != 0 &&
	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
			"overriding ap_scan configuration");
		wpa_s->conf->ap_scan = 0;
		wpas_notify_ap_scan_changed(wpa_s);
	}

	if (wpa_s->conf->ap_scan == 0) {
		wpa_supplicant_gen_assoc_event(wpa_s);
		return;
	}

#ifdef CONFIG_P2P
	if (wpas_p2p_in_progress(wpa_s)) {
		if (wpa_s->sta_scan_pending &&
		    wpas_p2p_in_progress(wpa_s) == 2 &&
		    wpa_s->global->p2p_cb_on_scan_complete) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
				"mode scan during P2P search");
		} else {
			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
				"while P2P operation is in progress");
			wpa_s->sta_scan_pending = 1;
			wpa_supplicant_req_scan(wpa_s, 5, 0);
			return;
		}
	}
#endif /* CONFIG_P2P */

	if (wpa_s->conf->ap_scan == 2)
		max_ssids = 1;
	else {
		max_ssids = wpa_s->max_scan_ssids;
		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
			max_ssids = WPAS_MAX_SCAN_SSIDS;
	}

	scan_req = wpa_s->scan_req;
	wpa_s->scan_req = 0;

	os_memset(&params, 0, sizeof(params));

	prev_state = wpa_s->wpa_state;
	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
	    wpa_s->wpa_state == WPA_INACTIVE)
		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);

	if (scan_req != 2 && wpa_s->connect_without_scan) {
		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
			if (ssid == wpa_s->connect_without_scan)
				break;
		}
		wpa_s->connect_without_scan = NULL;
		if (ssid) {
			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
				   "without scan step");
			wpa_supplicant_associate(wpa_s, NULL, ssid);
			return;
		}
	}

	/* Find the starting point from which to continue scanning */
	ssid = wpa_s->conf->ssid;
	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
		while (ssid) {
			if (ssid == wpa_s->prev_scan_ssid) {
				ssid = ssid->next;
				break;
			}
			ssid = ssid->next;
		}
	}

	if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
		wpa_s->connect_without_scan = NULL;
		wpa_s->prev_scan_wildcard = 0;
		wpa_supplicant_assoc_try(wpa_s, ssid);
		return;
#ifndef ANDROID
	} else if (wpa_s->conf->ap_scan == 2) {
		/*
		 * User-initiated scan request in ap_scan == 2; scan with
		 * wildcard SSID.
		 */
		ssid = NULL;
#endif
	} else {
		struct wpa_ssid *start = ssid, *tssid;
		int freqs_set = 0;
		if (ssid == NULL && max_ssids > 1)
			ssid = wpa_s->conf->ssid;
		while (ssid) {
			if (!ssid->disabled && ssid->scan_ssid) {
				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
						  ssid->ssid, ssid->ssid_len);
				params.ssids[params.num_ssids].ssid =
					ssid->ssid;
				params.ssids[params.num_ssids].ssid_len =
					ssid->ssid_len;
				params.num_ssids++;
				if (params.num_ssids + 1 >= max_ssids)
					break;
			}
			ssid = ssid->next;
			if (ssid == start)
				break;
			if (ssid == NULL && max_ssids > 1 &&
			    start != wpa_s->conf->ssid)
				ssid = wpa_s->conf->ssid;
		}

		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
			if (tssid->disabled)
				continue;
			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
				int_array_concat(&params.freqs,
						 tssid->scan_freq);
			} else {
				os_free(params.freqs);
				params.freqs = NULL;
			}
			freqs_set = 1;
		}
		int_array_sort_unique(params.freqs);
	}

	if (ssid && max_ssids == 1) {
		/*
		 * If the driver is limited to 1 SSID at a time interleave
		 * wildcard SSID scans with specific SSID scans to avoid
		 * waiting a long time for a wildcard scan.
		 */
		if (!wpa_s->prev_scan_wildcard) {
			params.ssids[0].ssid = NULL;
			params.ssids[0].ssid_len = 0;
			wpa_s->prev_scan_wildcard = 1;
			wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
				"wildcard SSID (Interleave with specific)");
		} else {
			wpa_s->prev_scan_ssid = ssid;
			wpa_s->prev_scan_wildcard = 0;
			wpa_dbg(wpa_s, MSG_DEBUG,
				"Starting AP scan for specific SSID: %s",
				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
		}
	} else if (ssid) {
		/* max_ssids > 1 */

		wpa_s->prev_scan_ssid = ssid;
		wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
			"the scan request");
		params.num_ssids++;
	} else {
		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
		params.num_ssids++;
		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
			"SSID");
	}

	wpa_supplicant_optimize_freqs(wpa_s, &params);
	extra_ie = wpa_supplicant_extra_ies(wpa_s, &params);

#ifdef CONFIG_HS20
	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
		wpas_hs20_add_indication(extra_ie);
#endif /* CONFIG_HS20 */

	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
			"generated frequency list");
		params.freqs = wpa_s->next_scan_freqs;
	} else
		os_free(wpa_s->next_scan_freqs);
	wpa_s->next_scan_freqs = NULL;

	params.filter_ssids = wpa_supplicant_build_filter_ssids(
		wpa_s->conf, &params.num_filter_ssids);
	if (extra_ie) {
		params.extra_ies = wpabuf_head(extra_ie);
		params.extra_ies_len = wpabuf_len(extra_ie);
	}

#ifdef CONFIG_P2P
	if (wpa_s->p2p_in_provisioning) {
		/*
		 * The interface may not yet be in P2P mode, so we have to
		 * explicitly request P2P probe to disable CCK rates.
		 */
		params.p2p_probe = 1;
	}
#endif /* CONFIG_P2P */

	ret = wpa_supplicant_trigger_scan(wpa_s, &params);

	wpabuf_free(extra_ie);
	os_free(params.freqs);
	os_free(params.filter_ssids);

	if (ret) {
		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
		if (prev_state != wpa_s->wpa_state)
			wpa_supplicant_set_state(wpa_s, prev_state);
		/* Restore scan_req since we will try to scan again */
		wpa_s->scan_req = scan_req;
		wpa_supplicant_req_scan(wpa_s, 1, 0);
	}
}
Exemple #18
0
int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
			       struct wpabuf **beacon_ret,
			       struct wpabuf **proberesp_ret,
			       struct wpabuf **assocresp_ret)
{
	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
	u8 buf[200], *pos;

	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;

	pos = buf;
	pos = hostapd_eid_time_adv(hapd, pos);
	if (pos != buf) {
		if (wpabuf_resize(&beacon, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(beacon, buf, pos - buf);
	}
	pos = hostapd_eid_time_zone(hapd, pos);
	if (pos != buf) {
		if (wpabuf_resize(&proberesp, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(proberesp, buf, pos - buf);
	}

	pos = buf;
	pos = hostapd_eid_ext_capab(hapd, pos);
	if (pos != buf) {
		if (wpabuf_resize(&assocresp, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(assocresp, buf, pos - buf);
	}
	pos = hostapd_eid_interworking(hapd, pos);
	pos = hostapd_eid_adv_proto(hapd, pos);
	pos = hostapd_eid_roaming_consortium(hapd, pos);
	if (pos != buf) {
		if (wpabuf_resize(&beacon, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(beacon, buf, pos - buf);

		if (wpabuf_resize(&proberesp, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(proberesp, buf, pos - buf);
	}

	if (hapd->wps_beacon_ie) {
		if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
		    0)
			goto fail;
		wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
	}

	if (hapd->wps_probe_resp_ie) {
		if (wpabuf_resize(&proberesp,
				  wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
			goto fail;
		wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
	}

#ifdef CONFIG_P2P
	if (hapd->p2p_beacon_ie) {
		if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
		    0)
			goto fail;
		wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
	}

	if (hapd->p2p_probe_resp_ie) {
		if (wpabuf_resize(&proberesp,
				  wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
			goto fail;
		wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
	}
#endif /* CONFIG_P2P */

#ifdef CONFIG_P2P_MANAGER
	if (hapd->conf->p2p & P2P_MANAGE) {
		if (wpabuf_resize(&beacon, 100) == 0) {
			u8 *start, *p;
			start = wpabuf_put(beacon, 0);
			p = hostapd_eid_p2p_manage(hapd, start);
			wpabuf_put(beacon, p - start);
		}

		if (wpabuf_resize(&proberesp, 100) == 0) {
			u8 *start, *p;
			start = wpabuf_put(proberesp, 0);
			p = hostapd_eid_p2p_manage(hapd, start);
			wpabuf_put(proberesp, p - start);
		}
	}
#endif /* CONFIG_P2P_MANAGER */

#ifdef CONFIG_WPS2
	if (hapd->conf->wps_state) {
		struct wpabuf *a = wps_build_assoc_resp_ie();
		if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
			wpabuf_put_buf(assocresp, a);
		wpabuf_free(a);
	}
#endif /* CONFIG_WPS2 */

#ifdef CONFIG_P2P_MANAGER
	if (hapd->conf->p2p & P2P_MANAGE) {
		if (wpabuf_resize(&assocresp, 100) == 0) {
			u8 *start, *p;
			start = wpabuf_put(assocresp, 0);
			p = hostapd_eid_p2p_manage(hapd, start);
			wpabuf_put(assocresp, p - start);
		}
	}
#endif /* CONFIG_P2P_MANAGER */

#ifdef CONFIG_WIFI_DISPLAY
	if (hapd->p2p_group) {
		struct wpabuf *a;
		a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
		if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
			wpabuf_put_buf(assocresp, a);
		wpabuf_free(a);
	}
#endif /* CONFIG_WIFI_DISPLAY */

#ifdef CONFIG_HS20
	pos = buf;
	pos = hostapd_eid_hs20_indication(hapd, pos);
	if (pos != buf) {
		if (wpabuf_resize(&beacon, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(beacon, buf, pos - buf);

		if (wpabuf_resize(&proberesp, pos - buf) != 0)
			goto fail;
		wpabuf_put_data(proberesp, buf, pos - buf);
	}
#endif /* CONFIG_HS20 */

	*beacon_ret = beacon;
	*proberesp_ret = proberesp;
	*assocresp_ret = assocresp;

	return 0;

fail:
	wpabuf_free(beacon);
	wpabuf_free(proberesp);
	wpabuf_free(assocresp);
	return -1;
}
Exemple #19
0
/**
 * tlsv1_client_decrypt - Decrypt data from TLS tunnel
 * @conn: TLSv1 client connection data from tlsv1_client_init()
 * @in_data: Pointer to input buffer (encrypted TLS data)
 * @in_len: Input buffer length
 * @need_more_data: Set to 1 if more data would be needed to complete
 *	processing
 * Returns: Decrypted data or %NULL on failure
 *
 * This function is used after TLS handshake has been completed successfully to
 * receive data from the encrypted tunnel.
 */
struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
				     const u8 *in_data, size_t in_len,
				     int *need_more_data)
{
	const u8 *in_end, *pos;
	int used;
	u8 alert, *out_pos, ct;
	size_t olen;
	struct wpabuf *buf = NULL;

	if (need_more_data)
		*need_more_data = 0;

	if (conn->partial_input) {
		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
				   "memory for pending record");
			alert = TLS_ALERT_INTERNAL_ERROR;
			goto fail;
		}
		wpabuf_put_data(conn->partial_input, in_data, in_len);
		in_data = wpabuf_head(conn->partial_input);
		in_len = wpabuf_len(conn->partial_input);
	}

	pos = in_data;
	in_end = in_data + in_len;

	while (pos < in_end) {
		ct = pos[0];
		if (wpabuf_resize(&buf, in_end - pos) < 0) {
			alert = TLS_ALERT_INTERNAL_ERROR;
			goto fail;
		}
		out_pos = wpabuf_put(buf, 0);
		olen = wpabuf_tailroom(buf);
		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
					    out_pos, &olen, &alert);
		if (used < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
				   "failed");
			goto fail;
		}
		if (used == 0) {
			struct wpabuf *partial;
			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
			partial = wpabuf_alloc_copy(pos, in_end - pos);
			wpabuf_free(conn->partial_input);
			conn->partial_input = partial;
			if (conn->partial_input == NULL) {
				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
					   "allocate memory for pending "
					   "record");
				alert = TLS_ALERT_INTERNAL_ERROR;
				goto fail;
			}
			if (need_more_data)
				*need_more_data = 1;
			return buf;
		}

		if (ct == TLS_CONTENT_TYPE_ALERT) {
			if (olen < 2) {
				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
					   "underflow");
				alert = TLS_ALERT_DECODE_ERROR;
				goto fail;
			}
			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
				   out_pos[0], out_pos[1]);
			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
				/* Continue processing */
				pos += used;
				continue;
			}

			alert = out_pos[1];
			goto fail;
		}

		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
				   "0x%x when decrypting application data",
				   pos[0]);
			alert = TLS_ALERT_UNEXPECTED_MESSAGE;
			goto fail;
		}

		wpabuf_put(buf, olen);

		pos += used;
	}

	wpabuf_free(conn->partial_input);
	conn->partial_input = NULL;
	return buf;

fail:
	wpabuf_free(buf);
	wpabuf_free(conn->partial_input);
	conn->partial_input = NULL;
	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
	return NULL;
}
Exemple #20
0
/**
 * tlsv1_client_handshake - Process TLS handshake
 * @conn: TLSv1 client connection data from tlsv1_client_init()
 * @in_data: Input data from TLS peer
 * @in_len: Input data length
 * @out_len: Length of the output buffer.
 * @appl_data: Pointer to application data pointer, or %NULL if dropped
 * @appl_data_len: Pointer to variable that is set to appl_data length
 * @need_more_data: Set to 1 if more data would be needed to complete
 *	processing
 * Returns: Pointer to output data, %NULL on failure
 */
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
			    const u8 *in_data, size_t in_len,
			    size_t *out_len, u8 **appl_data,
			    size_t *appl_data_len, int *need_more_data)
{
	const u8 *pos, *end;
	u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
	size_t in_msg_len;
	int no_appl_data;
	int used;

	if (need_more_data)
		*need_more_data = 0;

	if (conn->state == CLIENT_HELLO) {
		if (in_len)
			return NULL;
		return tls_send_client_hello(conn, out_len);
	}

	if (conn->partial_input) {
		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
				   "memory for pending record");
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
				  TLS_ALERT_INTERNAL_ERROR);
			goto failed;
		}
		wpabuf_put_data(conn->partial_input, in_data, in_len);
		in_data = wpabuf_head(conn->partial_input);
		in_len = wpabuf_len(conn->partial_input);
	}

	if (in_data == NULL || in_len == 0)
		return NULL;

	pos = in_data;
	end = in_data + in_len;
	in_msg = os_malloc(in_len);
	if (in_msg == NULL)
		return NULL;

	/* Each received packet may include multiple records */
	while (pos < end) {
		in_msg_len = in_len;
		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
					    in_msg, &in_msg_len, &alert);
		if (used < 0) {
			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
				   "record failed");
			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
			goto failed;
		}
		if (used == 0) {
			struct wpabuf *partial;
			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
			partial = wpabuf_alloc_copy(pos, end - pos);
			wpabuf_free(conn->partial_input);
			conn->partial_input = partial;
			if (conn->partial_input == NULL) {
				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
					   "allocate memory for pending "
					   "record");
				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
					  TLS_ALERT_INTERNAL_ERROR);
				goto failed;
			}
			os_free(in_msg);
			if (need_more_data)
				*need_more_data = 1;
			return NULL;
		}
		ct = pos[0];

		in_pos = in_msg;
		in_end = in_msg + in_msg_len;

		/* Each received record may include multiple messages of the
		 * same ContentType. */
		while (in_pos < in_end) {
			in_msg_len = in_end - in_pos;
			if (tlsv1_client_process_handshake(conn, ct, in_pos,
							   &in_msg_len,
							   appl_data,
							   appl_data_len) < 0)
				goto failed;
			in_pos += in_msg_len;
		}

		pos += used;
	}

	os_free(in_msg);
	in_msg = NULL;

	no_appl_data = appl_data == NULL || *appl_data == NULL;
	msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);

failed:
	os_free(in_msg);
	if (conn->alert_level) {
		wpabuf_free(conn->partial_input);
		conn->partial_input = NULL;
		conn->state = FAILED;
		os_free(msg);
		msg = tlsv1_client_send_alert(conn, conn->alert_level,
					      conn->alert_description,
					      out_len);
	} else if (msg == NULL) {
		msg = os_zalloc(1);
		*out_len = 0;
	}

	if (need_more_data == NULL || !(*need_more_data)) {
		wpabuf_free(conn->partial_input);
		conn->partial_input = NULL;
	}

	return msg;
}
static void eap_eke_process_commit(struct eap_sm *sm,
				   struct eap_eke_data *data,
				   const struct wpabuf *respData,
				   const u8 *payload, size_t payloadlen)
{
	const u8 *pos, *end, *dhcomp, *pnonce;
	size_t decrypt_len;

	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Commit");

	if (data->state != COMMIT) {
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	pos = payload;
	end = payload + payloadlen;

	if (pos + data->sess.dhcomp_len + data->sess.pnonce_len > end) {
		wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	wpa_hexdump(MSG_DEBUG, "EAP-EKE: DHComponent_P",
		    pos, data->sess.dhcomp_len);
	dhcomp = pos;
	pos += data->sess.dhcomp_len;
	wpa_hexdump(MSG_DEBUG, "EAP-EKE: PNonce_P", pos, data->sess.pnonce_len);
	pnonce = pos;
	pos += data->sess.pnonce_len;
	wpa_hexdump(MSG_DEBUG, "EAP-EKE: CBValue", pos, end - pos);

	if (eap_eke_shared_secret(&data->sess, data->key, data->dh_priv, dhcomp)
	    < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive shared secret");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}

	if (eap_eke_derive_ke_ki(&data->sess,
				 sm->server_id, sm->server_id_len,
				 data->peerid, data->peerid_len) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to derive Ke/Ki");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}

	decrypt_len = sizeof(data->nonce_p);
	if (eap_eke_decrypt_prot(&data->sess, pnonce, data->sess.pnonce_len,
				 data->nonce_p, &decrypt_len) < 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to decrypt PNonce_P");
		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
		return;
	}
	if (decrypt_len < (size_t) data->sess.nonce_len) {
		wpa_printf(MSG_INFO, "EAP-EKE: PNonce_P protected data too short to include Nonce_P");
		eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL);
		return;
	}
	wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Nonce_P",
			data->nonce_p, data->sess.nonce_len);

	if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}
	wpabuf_put_buf(data->msgs, respData);

	eap_eke_state(data, CONFIRM);
}
Exemple #22
0
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
	struct wpa_supplicant *wpa_s = eloop_ctx;
	struct wpa_ssid *ssid;
	int scan_req = 0, ret;
	struct wpabuf *wps_ie = NULL;
#ifdef CONFIG_WPS
	int wps = 0;
	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */
	struct wpa_driver_scan_params params;
	size_t max_ssids;
	enum wpa_states prev_state;

	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
		return;
	}

	if (wpa_s->disconnected && !wpa_s->scan_req) {
		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
		return;
	}

	if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
	    !wpa_s->scan_req) {
		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
		return;
	}

	if (wpa_s->conf->ap_scan != 0 &&
	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
			"overriding ap_scan configuration");
		wpa_s->conf->ap_scan = 0;
		wpas_notify_ap_scan_changed(wpa_s);
	}

	if (wpa_s->conf->ap_scan == 0) {
		wpa_supplicant_gen_assoc_event(wpa_s);
		return;
	}

	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
	    wpa_s->conf->ap_scan == 2)
		max_ssids = 1;
	else {
		max_ssids = wpa_s->max_scan_ssids;
		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
			max_ssids = WPAS_MAX_SCAN_SSIDS;
	}

#ifdef CONFIG_WPS
	wps = wpas_wps_in_use(wpa_s->conf, &req_type);
#endif /* CONFIG_WPS */

	scan_req = wpa_s->scan_req;
	wpa_s->scan_req = 0;

	os_memset(&params, 0, sizeof(params));

	prev_state = wpa_s->wpa_state;
	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
	    wpa_s->wpa_state == WPA_INACTIVE)
		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);

	/* Find the starting point from which to continue scanning */
	ssid = wpa_s->conf->ssid;
	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
		while (ssid) {
			if (ssid == wpa_s->prev_scan_ssid) {
				ssid = ssid->next;
				break;
			}
			ssid = ssid->next;
		}
	}

	if (scan_req != 2 && (wpa_s->conf->ap_scan == 2 ||
			      wpa_s->connect_without_scan)) {
		wpa_s->connect_without_scan = 0;
		wpa_supplicant_assoc_try(wpa_s, ssid);
		return;
	} else if (wpa_s->conf->ap_scan == 2) {
		/*
		 * User-initiated scan request in ap_scan == 2; scan with
		 * wildcard SSID.
		 */
		ssid = NULL;
	} else {
		struct wpa_ssid *start = ssid, *tssid;
		int freqs_set = 0;
		if (ssid == NULL && max_ssids > 1)
			ssid = wpa_s->conf->ssid;
		while (ssid) {
			if (!ssid->disabled && ssid->scan_ssid) {
				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
						  ssid->ssid, ssid->ssid_len);
				params.ssids[params.num_ssids].ssid =
					ssid->ssid;
				params.ssids[params.num_ssids].ssid_len =
					ssid->ssid_len;
				params.num_ssids++;
				if (params.num_ssids + 1 >= max_ssids)
					break;
			}
			ssid = ssid->next;
			if (ssid == start)
				break;
			if (ssid == NULL && max_ssids > 1 &&
			    start != wpa_s->conf->ssid)
				ssid = wpa_s->conf->ssid;
		}

		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
			if (tssid->disabled)
				continue;
			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
				int_array_concat(&params.freqs,
						 tssid->scan_freq);
			} else {
				os_free(params.freqs);
				params.freqs = NULL;
			}
			freqs_set = 1;
		}
		int_array_sort_unique(params.freqs);
	}

	if (ssid) {
		wpa_s->prev_scan_ssid = ssid;
		if (max_ssids > 1) {
			wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
				"the scan request");
			params.num_ssids++;
		}
		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for specific "
			"SSID(s)");
	} else {
		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
		params.num_ssids++;
		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
			"SSID");
	}

#ifdef CONFIG_P2P
	wpa_s->wps->dev.p2p = 1;
	if (!wps) {
		wps = 1;
		req_type = WPS_REQ_ENROLLEE_INFO;
	}

	if (params.freqs == NULL && wpa_s->p2p_in_provisioning &&
	    wpa_s->go_params) {
		/* Optimize provisioning state scan based on GO information */
		if (wpa_s->p2p_in_provisioning < 5 &&
		    wpa_s->go_params->freq > 0) {
			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
				"preferred frequency %d MHz",
				wpa_s->go_params->freq);
			params.freqs = os_zalloc(2 * sizeof(int));
			if (params.freqs)
				params.freqs[0] = wpa_s->go_params->freq;
		} else if (wpa_s->p2p_in_provisioning < 8 &&
			   wpa_s->go_params->freq_list[0]) {
			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
				"channels");
			int_array_concat(&params.freqs,
					 wpa_s->go_params->freq_list);
			if (params.freqs)
				int_array_sort_unique(params.freqs);
		}
		wpa_s->p2p_in_provisioning++;
	}
#endif /* CONFIG_P2P */

#ifdef CONFIG_WPS
	if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
		/*
		 * Optimize post-provisioning scan based on channel used
		 * during provisioning.
		 */
		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
			"that was used during provisioning", wpa_s->wps_freq);
		params.freqs = os_zalloc(2 * sizeof(int));
		if (params.freqs)
			params.freqs[0] = wpa_s->wps_freq;
		wpa_s->after_wps--;
	}

	if (wps) {
		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
						wpa_s->wps->uuid, req_type,
						0, NULL, wpa_s->wps->config_methods);
		if (wps_ie) {
			params.extra_ies = wpabuf_head(wps_ie);
			params.extra_ies_len = wpabuf_len(wps_ie);
		}
	}
#endif /* CONFIG_WPS */

#ifdef CONFIG_P2P
	if (wps_ie) {
		if (wpabuf_resize(&wps_ie, 100) == 0) {
			wpas_p2p_scan_ie(wpa_s, wps_ie);
			params.extra_ies = wpabuf_head(wps_ie);
			params.extra_ies_len = wpabuf_len(wps_ie);
		}
	}
#endif /* CONFIG_P2P */

	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
			"generated frequency list");
		params.freqs = wpa_s->next_scan_freqs;
	} else
		os_free(wpa_s->next_scan_freqs);
	wpa_s->next_scan_freqs = NULL;

	params.filter_ssids = wpa_supplicant_build_filter_ssids(
		wpa_s->conf, &params.num_filter_ssids);

	ret = wpa_supplicant_trigger_scan(wpa_s, &params);

	wpabuf_free(wps_ie);
	os_free(params.freqs);
	os_free(params.filter_ssids);

	if (ret) {
		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
		if (prev_state != wpa_s->wpa_state)
			wpa_supplicant_set_state(wpa_s, prev_state);
		wpa_supplicant_req_scan(wpa_s, 1, 0);
	}
}
void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa,
			      const u8 *data, size_t len, int rx_freq)
{
	const u8 *pos = data;
	const u8 *end = data + len;
	const u8 *next;
	u8 dialog_token;
	u16 status_code;
	u8 frag_id;
	u8 more_frags;
	u16 comeback_delay;
	u16 slen;

	wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len);

	if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
	    os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
		p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from "
			MACSTR, MAC2STR(sa));
		return;
	}
	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
	p2p_clear_timeout(p2p);

	p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)",
		MAC2STR(sa), (int) len);

	if (len < 6 + 2) {
		p2p_dbg(p2p, "Too short GAS Comeback Response frame");
		return;
	}

	dialog_token = *pos++;
	/* TODO: check dialog_token match */
	status_code = WPA_GET_LE16(pos);
	pos += 2;
	frag_id = *pos & 0x7f;
	more_frags = (*pos & 0x80) >> 7;
	pos++;
	comeback_delay = WPA_GET_LE16(pos);
	pos += 2;
	p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d "
		"comeback_delay=%u",
		dialog_token, status_code, frag_id, more_frags,
		comeback_delay);
	/* TODO: check frag_id match */
	if (status_code) {
		p2p_dbg(p2p, "Service Discovery failed: status code %u",
			status_code);
		return;
	}

	if (*pos != WLAN_EID_ADV_PROTO) {
		p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u",
			*pos);
		return;
	}
	pos++;

	slen = *pos++;
	next = pos + slen;
	if (next > end || slen < 2) {
		p2p_dbg(p2p, "Invalid IE in GAS Comeback Response");
		return;
	}
	pos++; /* skip QueryRespLenLimit and PAME-BI */

	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
		p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u",
			*pos);
		return;
	}

	pos = next;
	/* Query Response */
	if (pos + 2 > end) {
		p2p_dbg(p2p, "Too short Query Response");
		return;
	}
	slen = WPA_GET_LE16(pos);
	pos += 2;
	p2p_dbg(p2p, "Query Response Length: %d", slen);
	if (pos + slen > end) {
		p2p_dbg(p2p, "Not enough Query Response data");
		return;
	}
	if (slen == 0) {
		p2p_dbg(p2p, "No Query Response data");
		return;
	}
	end = pos + slen;

	if (p2p->sd_rx_resp) {
		 /*
		  * ANQP header is only included in the first fragment; rest of
		  * the fragments start with continue TLVs.
		  */
		goto skip_nqp_header;
	}

	/* ANQP Query Response */
	if (pos + 4 > end)
		return;
	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
		p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
		return;
	}
	pos += 2;

	slen = WPA_GET_LE16(pos);
	pos += 2;
	p2p_dbg(p2p, "ANQP Query Response length: %u", slen);
	if (slen < 3 + 1) {
		p2p_dbg(p2p, "Invalid ANQP Query Response length");
		return;
	}
	if (pos + 4 > end)
		return;

	if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) {
		p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x",
			WPA_GET_BE32(pos));
		return;
	}
	pos += 4;

	if (pos + 2 > end)
		return;
	p2p->sd_rx_update_indic = WPA_GET_LE16(pos);
	p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic);
	pos += 2;

skip_nqp_header:
	if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0)
		return;
	wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos);
	p2p_dbg(p2p, "Current SD reassembly buffer length: %u",
		(unsigned int) wpabuf_len(p2p->sd_rx_resp));

	if (more_frags) {
		p2p_dbg(p2p, "More fragments remains");
		/* TODO: what would be a good size limit? */
		if (wpabuf_len(p2p->sd_rx_resp) > 64000) {
			wpabuf_free(p2p->sd_rx_resp);
			p2p->sd_rx_resp = NULL;
			p2p_dbg(p2p, "Too long SD response - drop it");
			return;
		}
		p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq);
		return;
	}

	p2p->sd_peer = NULL;

	if (p2p->sd_query) {
		if (!p2p->sd_query->for_all_peers) {
			struct p2p_sd_query *q;
			p2p_dbg(p2p, "Remove completed SD query %p",
				p2p->sd_query);
			q = p2p->sd_query;
			p2p_unlink_sd_query(p2p, p2p->sd_query);
			p2p_free_sd_query(q);
		}
		p2p->sd_query = NULL;
	}

	if (p2p->cfg->sd_response)
		p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa,
				      p2p->sd_rx_update_indic,
				      wpabuf_head(p2p->sd_rx_resp),
				      wpabuf_len(p2p->sd_rx_resp));
	wpabuf_free(p2p->sd_rx_resp);
	p2p->sd_rx_resp = NULL;

	p2p_continue_find(p2p);
}
static void eap_eke_process_identity(struct eap_sm *sm,
				     struct eap_eke_data *data,
				     const struct wpabuf *respData,
				     const u8 *payload, size_t payloadlen)
{
	const u8 *pos, *end;
	int i;

	wpa_printf(MSG_DEBUG, "EAP-EKE: Received Response/Identity");

	if (data->state != IDENTITY) {
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	pos = payload;
	end = payload + payloadlen;

	if (pos + 2 + 4 + 1 > end) {
		wpa_printf(MSG_INFO, "EAP-EKE: Too short EAP-EKE-ID payload");
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	if (*pos != 1) {
		wpa_printf(MSG_INFO, "EAP-EKE: Unexpected NumProposals %d (expected 1)",
			   *pos);
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	pos += 2;

	if (!supported_proposal(pos)) {
		wpa_printf(MSG_INFO, "EAP-EKE: Unexpected Proposal (%u:%u:%u:%u)",
			   pos[0], pos[1], pos[2], pos[3]);
		eap_eke_fail(data, EAP_EKE_FAIL_PROTO_ERROR);
		return;
	}

	wpa_printf(MSG_DEBUG, "EAP-EKE: Selected Proposal (%u:%u:%u:%u)",
		   pos[0], pos[1], pos[2], pos[3]);
	if (eap_eke_session_init(&data->sess, pos[0], pos[1], pos[2], pos[3]) <
	    0) {
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}
	pos += 4;

	data->peerid_type = *pos++;
	os_free(data->peerid);
	data->peerid = os_memdup(pos, end - pos);
	if (data->peerid == NULL) {
		wpa_printf(MSG_INFO, "EAP-EKE: Failed to allocate memory for peerid");
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}
	data->peerid_len = end - pos;
	wpa_printf(MSG_DEBUG, "EAP-EKE: Peer IDType %u", data->peerid_type);
	wpa_hexdump_ascii(MSG_DEBUG, "EAP-EKE: Peer Identity",
			  data->peerid, data->peerid_len);

	if (eap_user_get(sm, data->peerid, data->peerid_len, data->phase2)) {
		wpa_printf(MSG_INFO, "EAP-EKE: Peer Identity not found from user database");
		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
		return;
	}

	for (i = 0; i < EAP_MAX_METHODS; i++) {
		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
		    sm->user->methods[i].method == EAP_TYPE_EKE)
			break;
	}
	if (i == EAP_MAX_METHODS) {
		wpa_printf(MSG_INFO, "EAP-EKE: Matching user entry does not allow EAP-EKE");
		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
		return;
	}

	if (sm->user->password == NULL || sm->user->password_len == 0) {
		wpa_printf(MSG_INFO, "EAP-EKE: No password configured for peer");
		eap_eke_fail(data, EAP_EKE_FAIL_PASSWD_NOT_FOUND);
		return;
	}

	if (wpabuf_resize(&data->msgs, wpabuf_len(respData)) < 0) {
		eap_eke_fail(data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
		return;
	}
	wpabuf_put_buf(data->msgs, respData);

	eap_eke_state(data, COMMIT);
}