int p2p_parse_ies_separate(const u8 *wsc, size_t wsc_len, const u8 *p2p,
			   size_t p2p_len, struct p2p_message *msg)
{
	os_memset(msg, 0, sizeof(*msg));

	msg->wps_attributes = wpabuf_alloc_copy(wsc, wsc_len);
	if (msg->wps_attributes &&
	    p2p_parse_wps_ie(msg->wps_attributes, msg)) {
		p2p_parse_free(msg);
		return -1;
	}

	msg->p2p_attributes = wpabuf_alloc_copy(p2p, p2p_len);
	if (msg->p2p_attributes &&
	    p2p_parse_p2p_ie(msg->p2p_attributes, msg)) {
		wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P IE data");
		if (msg->p2p_attributes)
			wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P IE data",
					msg->p2p_attributes);
		p2p_parse_free(msg);
		return -1;
	}

	return 0;
}
Beispiel #2
0
static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
			      size_t pk_len)
{
	if (pk == NULL || pk_len == 0) {
		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
		return -1;
	}

#ifdef CONFIG_WPS_OOB
	if (wps->dev_pw_id != DEV_PW_DEFAULT &&
	    wps->wps->oob_conf.pubkey_hash) {
		const u8 *addr[1];
		u8 hash[WPS_HASH_LEN];

		addr[0] = pk;
		sha256_vector(1, addr, &pk_len, hash);
		if (os_memcmp(hash,
			      wpabuf_head(wps->wps->oob_conf.pubkey_hash),
			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
			wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
			return -1;
		}
	}
#endif /* CONFIG_WPS_OOB */

	wpabuf_free(wps->dh_pubkey_r);
	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
	if (wps->dh_pubkey_r == NULL)
		return -1;

	if (wps_derive_keys(wps) < 0)
		return -1;

	return 0;
}
void eap_example_peer_rx(const u8 *data, size_t data_len)
{
	/* Make received EAP message available to the EAP library */
	eap_ctx.eapReq = TRUE;
	wpabuf_free(eap_ctx.eapReqData);
	eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
}
void eap_peer_rx(const void *data, int data_len)
{
	//wpa_hexdump(MSG_DEBUG, "lala EAP Server send", data, data_len);  //Server send to peer :)
	eap_ctx.eapReq = TRUE;
	//wpabuf_free(eap_ctx.eapReqData);
	eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
}
int p2p_group_notif_noa(struct p2p_group *group, const u8 *noa,
			size_t noa_len)
{
	if (noa == NULL) {
		wpabuf_free(group->noa);
		group->noa = NULL;
	} else {
		if (group->noa) {
			if (wpabuf_size(group->noa) >= noa_len) {
				group->noa->used = 0;
				wpabuf_put_data(group->noa, noa, noa_len);
			} else {
				wpabuf_free(group->noa);
				group->noa = NULL;
			}
		}

		if (!group->noa) {
			group->noa = wpabuf_alloc_copy(noa, noa_len);
			if (group->noa == NULL)
				return -1;
		}
	}

	group->beacon_update = 1;
	p2p_group_update_ies(group);
	return 0;
}
Beispiel #6
0
static void gas_query_rx_initial(struct gas_query *gas,
				 struct gas_query_pending *query,
				 const u8 *adv_proto, const u8 *resp,
				 size_t len, u16 comeback_delay)
{
	wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
		   MACSTR " (dialog_token=%u comeback_delay=%u)",
		   MAC2STR(query->addr), query->dialog_token, comeback_delay);

	query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
	if (query->adv_proto == NULL) {
		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
		return;
	}

	if (comeback_delay) {
		query->wait_comeback = 1;
		gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
		return;
	}

	/* Query was completed without comeback mechanism */
	if (gas_query_append(query, resp, len) < 0) {
		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
		return;
	}

	gas_query_done(gas, query, GAS_QUERY_SUCCESS);
}
Beispiel #7
0
static struct wpabuf * read_nfc(void *priv)
{
	struct wps_nfc_data *data = priv;
	struct wpabuf *wifi, *buf;
	char *raw_data;
	size_t len;

	raw_data = data->oob_nfc_dev->read_func(&len);
	if (raw_data == NULL)
		return NULL;

	wifi = wpabuf_alloc_copy(raw_data, len);
	os_free(raw_data);
	if (wifi == NULL) {
		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to allocate "
			   "nfc read area");
		return NULL;
	}

	buf = ndef_parse_wifi(wifi);
	wpabuf_free(wifi);
	if (buf == NULL)
		wpa_printf(MSG_ERROR, "WPS (NFC): Failed to unwrap");
	return buf;
}
Beispiel #8
0
static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
					       struct tls_connection *conn)
{
	DWORD sspi_flags, sspi_flags_out;
	SecBufferDesc outbuf;
	SecBuffer outbufs[1];
	SECURITY_STATUS status;
	TimeStamp ts_expiry;

	sspi_flags = ISC_REQ_REPLAY_DETECT |
		ISC_REQ_CONFIDENTIALITY |
		ISC_RET_EXTENDED_ERROR |
		ISC_REQ_ALLOCATE_MEMORY |
		ISC_REQ_MANUAL_CRED_VALIDATION;

	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);

	outbufs[0].pvBuffer = NULL;
	outbufs[0].BufferType = SECBUFFER_TOKEN;
	outbufs[0].cbBuffer = 0;

	outbuf.cBuffers = 1;
	outbuf.pBuffers = outbufs;
	outbuf.ulVersion = SECBUFFER_VERSION;

#ifdef UNICODE
	status = global->sspi->InitializeSecurityContextW(
		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
		&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
	status = global->sspi->InitializeSecurityContextA(
		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
		&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
	if (status != SEC_I_CONTINUE_NEEDED) {
		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
			   "failed - 0x%x",
			   __func__, (unsigned int) status);
		return NULL;
	}

	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
		struct wpabuf *buf;
		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
		conn->start = 0;
		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
					outbufs[0].cbBuffer);
		if (buf == NULL)
			return NULL;
		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
		return buf;
	}

	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");

	return NULL;
}
Beispiel #9
0
static int ikev2_process_ker(struct ikev2_initiator_data *data,
			     const u8 *ker, size_t ker_len)
{
	u16 group;

	/*
	 * Key Exchange Payload:
	 * DH Group # (16 bits)
	 * RESERVED (16 bits)
	 * Key Exchange Data (Diffie-Hellman public value)
	 */

	if (ker == NULL) {
		asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: KEr not received");
		return -1;
	}

	if (ker_len < 4 + 96) {
		asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Too show Key Exchange Payload");
		return -1;
	}

	group = WPA_GET_BE16(ker);
	asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: KEr DH Group #%u", group);

	if (group != data->proposal.dh) {
		asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: KEr DH Group #%u does not match "
			   "with the selected proposal (%u)",
			   group, data->proposal.dh);
		return -1;
	}

	if (data->dh == NULL) {
		asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Unsupported DH group");
		return -1;
	}

	/* RFC 4306, Section 3.4:
	 * The length of DH public value MUST be equal to the lenght of the
	 * prime modulus.
	 */
	if (ker_len - 4 != data->dh->prime_len) {
		asd_printf(ASD_DEFAULT,MSG_DEBUG, "IKEV2: Invalid DH public value length "
			   "%ld (expected %ld)",
			   (long) (ker_len - 4), (long) data->dh->prime_len);
		return -1;
	}

	wpabuf_free(data->r_dh_public);
	data->r_dh_public = wpabuf_alloc_copy(ker + 4, ker_len - 4);
	if (data->r_dh_public == NULL)
		return -1;

	wpa_hexdump_buf(MSG_DEBUG, "IKEV2: KEr Diffie-Hellman Public Value",
			data->r_dh_public);
	
	return 0;
}
int wifi_display_subelem_set_from_ies(struct wpa_global *global,
				      struct wpabuf *ie)
{
	int subelements[MAX_WFD_SUBELEMS] = {};
	const u8 *pos, *end;
	int len, subelem;
	struct wpabuf *e;

	wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
		   ie, ie ? (unsigned long) wpabuf_len(ie) : 0);

	if (ie == NULL || wpabuf_len(ie) < 6)
		return -1;

	pos = wpabuf_head(ie);
	end = pos + wpabuf_len(ie);

	while (end > pos) {
		if (pos + 3 > end)
			break;

		len = WPA_GET_BE16(pos + 1) + 3;

		wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
			   *pos, len - 3);

		if (pos + len > end)
			break;

		subelem = *pos;
		if (subelem < MAX_WFD_SUBELEMS && subelements[subelem] == 0) {
			e = wpabuf_alloc_copy(pos, len);
			if (e == NULL)
				return -1;

			wpabuf_free(global->wfd_subelem[subelem]);
			global->wfd_subelem[subelem] = e;
			subelements[subelem] = 1;
		}

		pos += len;
	}

	for (subelem = 0; subelem < MAX_WFD_SUBELEMS; subelem++) {
		if (subelements[subelem] == 0) {
			wpabuf_free(global->wfd_subelem[subelem]);
			global->wfd_subelem[subelem] = NULL;
		}
	}

	return wifi_display_update_wfd_ie(global);
}
Beispiel #11
0
/* Processes a received WPS message and returns the message type */
enum wps_type process_wps_message(const void *data, size_t data_size) {
    const struct wpabuf *msg = NULL;
    enum wps_type type = UNKNOWN;
    struct wps_data *wps = get_wps();
    unsigned char *element_data = NULL;
    struct wfa_element_header element = {0};
    int i = 0, header_size = sizeof (struct wfa_element_header);

    /* Shove data into a wpabuf structure for processing */
    msg = wpabuf_alloc_copy(data, data_size);
    if (msg) {
        /* Process the incoming message */
        wps_registrar_process_msg(wps, get_opcode(), msg);
        wpabuf_free((struct wpabuf *) msg);

        /* Loop through until we hit the end of the data buffer */
        for (i = 0; i < data_size; i += header_size) {
            element_data = NULL;
            memset((void *) &element, 0, header_size);

            /* Get the element header data */
            memcpy((void *) &element, (data + i), header_size);
            element.type = htons(element.type);
            element.length = htons(element.length);

            /* Make sure the element length does not exceed the remaining buffer size */
            if (element.length <= (data_size - i - header_size)) {
                element_data = (unsigned char *) (data + i + header_size);

                switch (element.type) {
                    case MESSAGE_TYPE:
                        type = (uint8_t) element_data[0];
                        break;
                    case CONFIGURATION_ERROR:
                        /* Check element_data length */
                        if (element.length == 2)
                            set_nack_reason(htons(*((uint16_t*) element_data)));
                        break;
                    default:
                        break;
                }
            }

            /* Offset must include element length(s) */
            i += element.length;
        }

    }

    return type;
}
Beispiel #12
0
static int
atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
{
	struct atheros_driver_data *drv = priv;
	u8 buf[512];
	struct ieee80211req_getset_appiebuf *app_ie;

	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
		   (unsigned long) ie_len);

	wpabuf_free(drv->wpa_ie);
	drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);

	app_ie = (struct ieee80211req_getset_appiebuf *) buf;
	os_memcpy(&(app_ie->app_buf[0]), ie, ie_len);
	app_ie->app_buflen = ie_len;

	app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON;

	/* append WPS IE for Beacon */
	if (drv->wps_beacon_ie != NULL) {
		os_memcpy(&(app_ie->app_buf[ie_len]),
			  wpabuf_head(drv->wps_beacon_ie),
			  wpabuf_len(drv->wps_beacon_ie));
		app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
	}
	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
		     sizeof(struct ieee80211req_getset_appiebuf) +
		     app_ie->app_buflen);

	/* append WPS IE for Probe Response */
	app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP;
	if (drv->wps_probe_resp_ie != NULL) {
		os_memcpy(&(app_ie->app_buf[ie_len]),
			  wpabuf_head(drv->wps_probe_resp_ie),
			  wpabuf_len(drv->wps_probe_resp_ie));
		app_ie->app_buflen = ie_len +
			wpabuf_len(drv->wps_probe_resp_ie);
	} else
		app_ie->app_buflen = ie_len;
	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
		     sizeof(struct ieee80211req_getset_appiebuf) +
		     app_ie->app_buflen);
	return 0;
}
Beispiel #13
0
static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
			      size_t pk_len)
{
	if (pk == NULL || pk_len == 0) {
		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
		return -1;
	}

	wpabuf_free(wps->dh_pubkey_r);
	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
	if (wps->dh_pubkey_r == NULL)
		return -1;

	if (wps_derive_keys(wps) < 0)
		return -1;

	return 0;
}
Beispiel #14
0
/* 
 * Get the reason code for a WSC NACK message. Not really useful because in practice the NACK
 * reason code could be anything (even a non-existent code!), but keep it around just in case... 
 */
int parse_nack(const void *data, size_t data_size) {
    struct wps_parse_attr attr = {0};
    const struct wpabuf *msg = NULL;
    int ret_val = 0;

    /* Shove data into a wpabuf structure for processing */
    msg = wpabuf_alloc_copy(data, data_size);
    if (msg) {
        if (wps_parse_msg(msg, &attr) >= 0) {
            if (attr.config_error) {
                ret_val = WPA_GET_BE16(attr.config_error);
            }
        }

        wpabuf_free((struct wpabuf *) msg);
    }

    return ret_val;
}
Beispiel #15
0
static int wps_parse_oob_dev_pwd(struct wps_context *wps,
				 struct wpabuf *data)
{
	struct oob_conf_data *oob_conf = &wps->oob_conf;
	struct wps_parse_attr attr;
	const u8 *pos;

	if (wps_parse_msg(data, &attr) < 0 ||
	    attr.oob_dev_password == NULL) {
		wpa_printf(MSG_ERROR, "WPS: OOB device password not found");
		return -1;
	}

	pos = attr.oob_dev_password;

	oob_conf->pubkey_hash =
		wpabuf_alloc_copy(pos, WPS_OOB_PUBKEY_HASH_LEN);
	if (oob_conf->pubkey_hash == NULL) {
		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
			   "public key hash");
		return -1;
	}
	pos += WPS_OOB_PUBKEY_HASH_LEN;

	wps->oob_dev_pw_id = WPA_GET_BE16(pos);
	pos += sizeof(wps->oob_dev_pw_id);

	oob_conf->dev_password =
		wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN * 2 + 1);
	if (oob_conf->dev_password == NULL) {
		wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
			   "device password");
		return -1;
	}
	wpa_snprintf_hex_uppercase(wpabuf_put(oob_conf->dev_password,
				   wpabuf_size(oob_conf->dev_password)),
				   wpabuf_size(oob_conf->dev_password), pos,
				   WPS_OOB_DEVICE_PASSWORD_LEN);

	return 0;
}
Beispiel #16
0
static struct wpabuf * ndef_parse_records(struct wpabuf *buf,
					  int (*filter)(struct ndef_record *))
{
	struct ndef_record record;
	int len = wpabuf_len(buf);
	u8 *data = wpabuf_mhead(buf);

	while (len > 0) {
		if (ndef_parse_record(data, len, &record) < 0) {
			wpa_printf(MSG_ERROR, "NDEF : Failed to parse");
			return NULL;
		}
		if (filter == NULL || filter(&record))
			return wpabuf_alloc_copy(record.payload,
						 record.payload_length);
		data += record.total_length;
		len -= record.total_length;
	}
	wpa_printf(MSG_ERROR, "NDEF : Record not found");
	return NULL;
}
Beispiel #17
0
static void gnutls_tls_fail_event(struct tls_connection *conn,
				  const gnutls_datum_t *cert, int depth,
				  const char *subject, const char *err_str,
				  enum tls_fail_reason reason)
{
	union tls_event_data ev;
	struct tls_global *global = conn->global;
	struct wpabuf *cert_buf = NULL;

	if (global->event_cb == NULL)
		return;

	os_memset(&ev, 0, sizeof(ev));
	ev.cert_fail.depth = depth;
	ev.cert_fail.subject = subject ? subject : "";
	ev.cert_fail.reason = reason;
	ev.cert_fail.reason_txt = err_str;
	if (cert) {
		cert_buf = wpabuf_alloc_copy(cert->data, cert->size);
		ev.cert_fail.cert = cert_buf;
	}
	global->event_cb(global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
	wpabuf_free(cert_buf);
}
static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
			      size_t pk_len)
{
	if (pk == NULL || pk_len == 0) {
		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
		return -1;
	}

	if (wps->peer_pubkey_hash_set) {
		u8 hash[WPS_HASH_LEN];
		sha256_vector(1, &pk, &pk_len, hash);
		if (os_memcmp(hash, wps->peer_pubkey_hash,
			      WPS_OOB_PUBKEY_HASH_LEN) != 0) {
			wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch");
			wpa_hexdump(MSG_DEBUG, "WPS: Received public key",
				    pk, pk_len);
			wpa_hexdump(MSG_DEBUG, "WPS: Calculated public key "
				    "hash", hash, WPS_OOB_PUBKEY_HASH_LEN);
			wpa_hexdump(MSG_DEBUG, "WPS: Expected public key hash",
				    wps->peer_pubkey_hash,
				    WPS_OOB_PUBKEY_HASH_LEN);
			wps->config_error = WPS_CFG_PUBLIC_KEY_HASH_MISMATCH;
			return -1;
		}
	}

	wpabuf_free(wps->dh_pubkey_r);
	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
	if (wps->dh_pubkey_r == NULL)
		return -1;

	if (wps_derive_keys(wps) < 0)
		return -1;

	return 0;
}
Beispiel #19
0
static int eap_peap_phase2_request(struct eap_sm *sm,
				   struct eap_peap_data *data,
				   struct eap_method_ret *ret,
				   struct wpabuf *req,
				   struct wpabuf **resp)
{
	struct eap_hdr *hdr = wpabuf_mhead(req);
	size_t len = be_to_host16(hdr->length);
	u8 *pos;
	struct eap_method_ret iret;
	struct eap_peer_config *config = eap_get_config(sm);

	if (len <= sizeof(struct eap_hdr)) {
		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
			   "Phase 2 request (len=%lu)", (unsigned long) len);
		return -1;
	}
	pos = (u8 *) (hdr + 1);
	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
	switch (*pos) {
	case EAP_TYPE_IDENTITY:
		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
		break;
	case EAP_TYPE_TLV:
		os_memset(&iret, 0, sizeof(iret));
		if (eap_tlv_process(sm, data, &iret, req, resp,
				    data->phase2_eap_started &&
				    !data->phase2_eap_success)) {
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return -1;
		}
		if (iret.methodState == METHOD_DONE ||
		    iret.methodState == METHOD_MAY_CONT) {
			ret->methodState = iret.methodState;
			ret->decision = iret.decision;
			data->phase2_success = 1;
		}
		break;
	case EAP_TYPE_EXPANDED:
#ifdef EAP_TNC
		if (data->soh) {
			const u8 *epos;
			size_t eleft;

			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
						req, &eleft);
			if (epos) {
				struct wpabuf *buf;
				wpa_printf(MSG_DEBUG,
					   "EAP-PEAP: SoH EAP Extensions");
				buf = tncc_process_soh_request(data->soh,
							       epos, eleft);
				if (buf) {
					*resp = eap_msg_alloc(
						EAP_VENDOR_MICROSOFT, 0x21,
						wpabuf_len(buf),
						EAP_CODE_RESPONSE,
						hdr->identifier);
					if (*resp == NULL) {
						ret->methodState = METHOD_DONE;
						ret->decision = DECISION_FAIL;
						return -1;
					}
					wpabuf_put_buf(*resp, buf);
					wpabuf_free(buf);
					break;
				}
			}
		}
#endif /* EAP_TNC */
		/* fall through */
	default:
		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
		    data->phase2_type.method == EAP_TYPE_NONE) {
			size_t i;
			for (i = 0; i < data->num_phase2_types; i++) {
				if (data->phase2_types[i].vendor !=
				    EAP_VENDOR_IETF ||
				    data->phase2_types[i].method != *pos)
					continue;

				data->phase2_type.vendor =
					data->phase2_types[i].vendor;
				data->phase2_type.method =
					data->phase2_types[i].method;
				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
					   "Phase 2 EAP vendor %d method %d",
					   data->phase2_type.vendor,
					   data->phase2_type.method);
				break;
			}
		}
		if (*pos != data->phase2_type.method ||
		    *pos == EAP_TYPE_NONE) {
			if (eap_peer_tls_phase2_nak(data->phase2_types,
						    data->num_phase2_types,
						    hdr, resp))
				return -1;
			return 0;
		}

		if (data->phase2_priv == NULL) {
			data->phase2_method = eap_peer_get_eap_method(
				data->phase2_type.vendor,
				data->phase2_type.method);
			if (data->phase2_method) {
				sm->init_phase2 = 1;
				data->phase2_priv =
					data->phase2_method->init(sm);
				sm->init_phase2 = 0;
			}
		}
		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
				   "Phase 2 EAP method %d", *pos);
			ret->methodState = METHOD_DONE;
			ret->decision = DECISION_FAIL;
			return -1;
		}
		data->phase2_eap_started = 1;
		os_memset(&iret, 0, sizeof(iret));
		*resp = data->phase2_method->process(sm, data->phase2_priv,
						     &iret, req);
		if ((iret.methodState == METHOD_DONE ||
		     iret.methodState == METHOD_MAY_CONT) &&
		    (iret.decision == DECISION_UNCOND_SUCC ||
		     iret.decision == DECISION_COND_SUCC)) {
			data->phase2_eap_success = 1;
			data->phase2_success = 1;
		}
		break;
	}

	if (*resp == NULL &&
	    (config->pending_req_identity || config->pending_req_password ||
	     config->pending_req_otp || config->pending_req_new_password)) {
		wpabuf_free(data->pending_phase2_req);
		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
	}

	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;
}
/*
 *	Do EAP.
 */
static rlm_rcode_t eap_authenticate(void *instance, REQUEST *request)
{
	rlm_eap_t	*inst;
	EAP_HANDLER	*handler;
	void		*data;
	int		data_len;
	rlm_rcode_t	rcode;
	VALUE_PAIR	*vp;

	inst = (rlm_eap_t *) instance;

	vp = pairfind(request->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
	if (!vp) {
		RDEBUG("No EAP-Message.  Not doing EAP.");
		return RLM_MODULE_FAIL;
	}

	/*
	 *	Get the eap packet  to start with
	 */
	data = NULL;
	data_len = 0;
	if (eap_vp2data(request->packet->vps, &data, &data_len) < 0) {
		radlog(L_ERR, "rlm_eap2: Malformed EAP Message");
		return RLM_MODULE_FAIL;
	}

	vp = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
	if (vp) {
		handler = eaplist_find(inst, request);
		if (!handler) {
			RDEBUG("No handler found");
			return RLM_MODULE_FAIL;
		}
	} else {
		handler = malloc(sizeof(*handler));
		if (!handler) return RLM_MODULE_FAIL;

		memset(handler, 0, sizeof(*handler));

		handler->inst = inst;
		handler->eap_cb.get_eap_user = server_get_eap_user;
		handler->eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;

		handler->eap_conf.eap_server = 1;
		handler->eap_conf.ssl_ctx = inst->tls_ctx;

		/*
		 *	Copy EAP-FAST parameters.
		 */
		handler->eap_conf.pac_opaque_encr_key = inst->pac_opaque_encr_key; 
		handler->eap_conf.eap_fast_a_id = inst->eap_fast_a_id; 
		handler->eap_conf.eap_fast_a_id_len = strlen(inst->eap_fast_a_id); 
		handler->eap_conf.eap_fast_a_id_info = inst->eap_fast_a_id_info; 
		handler->eap_conf.eap_fast_prov = inst->eap_fast_prov; 
		handler->eap_conf.pac_key_lifetime = inst->pac_key_lifetime; 
		handler->eap_conf.pac_key_refresh_time = inst->pac_key_refresh_time; 
		handler->eap_conf.backend_auth = inst->backend_auth; 
		
		handler->server_ctx.eap = eap_server_sm_init(handler,
							     &handler->eap_cb,
							     &handler->eap_conf);
		if (handler->server_ctx.eap == NULL) {
			free(handler);
			return RLM_MODULE_FAIL;
		}
		
		handler->server_ctx.eap_if = eap_get_interface(handler->server_ctx.eap);
		
		/* Enable "port" and request EAP to start authentication. */
		handler->server_ctx.eap_if->portEnabled = TRUE;
		handler->server_ctx.eap_if->eapRestart = TRUE;
	}

	handler->request = request;
	wpabuf_free(handler->server_ctx.eap_if->eapRespData);
	handler->server_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
	if (handler->server_ctx.eap_if->eapRespData) {
		handler->server_ctx.eap_if->eapResp = TRUE;
	}
	
	if (eap_example_server_step(handler) < 0) {
		RDEBUG("Failed in EAP library");
		goto fail;
	}

	if (handler->server_ctx.eap_if->eapSuccess) {
		request->reply->code = PW_AUTHENTICATION_ACK;
		rcode = RLM_MODULE_OK;

	} else if (handler->server_ctx.eap_if->eapFail) {
	fail:
		request->reply->code = PW_AUTHENTICATION_REJECT;
		rcode = RLM_MODULE_REJECT;

	} else {
		request->reply->code = PW_ACCESS_CHALLENGE;
		rcode = RLM_MODULE_HANDLED;
	}

	if (handler->server_ctx.eap_if->eapFail ||
	    handler->server_ctx.eap_if->eapSuccess) {
		RDEBUG2("Freeing handler");
		/* handler is not required any more, free it now */
		eap_handler_free(handler);
		handler = NULL;
	} else {
		eaplist_add(inst, handler);
	}

	/*
	 *	If it's an Access-Accept, RFC 2869, Section 2.3.1
	 *	says that we MUST include a User-Name attribute in the
	 *	Access-Accept.
	 */
	if ((request->reply->code == PW_AUTHENTICATION_ACK) &&
	    request->username) {
		/*
		 *	Doesn't exist, add it in.
		 */
		vp = pairfind(request->reply->vps, PW_USER_NAME, 0, TAG_ANY);
		if (!vp) {
			vp = pairmake("User-Name", request->username->vp_strvalue,
				      T_OP_EQ);
			rad_assert(vp != NULL);
			pairadd(&(request->reply->vps), vp);
		}

		/*
		 *	Cisco AP1230 has a bug and needs a zero
		 *	terminated string in Access-Accept.
		 */
		if ((inst->cisco_accounting_username_bug) &&
		    (vp->length < (int) sizeof(vp->vp_strvalue))) {
			vp->vp_strvalue[vp->length] = '\0';
			vp->length++;
		}
	}

	vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
	if (!vp) {
		vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
		memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
		vp->length = AUTH_VECTOR_LEN;
		pairadd(&(request->reply->vps), vp);
	}
	return rcode;
}
Beispiel #22
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;
}
Beispiel #23
0
static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
					 const u8 *sa,
					 const u8 *data, size_t len)
{
	struct gas_dialog_info *dialog;
	struct wpabuf *buf, *tx_buf;
	u8 dialog_token;
	size_t frag_len;
	int more = 0;

	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
	if (len < 1)
		return;
	dialog_token = *data;
	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
		dialog_token);

	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
	if (!dialog) {
		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
			"response fragment for " MACSTR " dialog token %u",
			MAC2STR(sa), dialog_token);

		if (sa[0] & 0x01)
			return; /* Invalid source address - drop silently */
		tx_buf = gas_anqp_build_comeback_resp_buf(
			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
			0, NULL);
		if (tx_buf == NULL)
			return;
		goto send_resp;
	}

	if (dialog->sd_resp == NULL) {
		wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
			   dialog->requested, dialog->received);
		if ((dialog->requested & dialog->received) !=
		    dialog->requested) {
			wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
				   "from remote processing");
			gas_serv_dialog_clear(dialog);
			tx_buf = gas_anqp_build_comeback_resp_buf(
				dialog_token,
				WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
				NULL);
			if (tx_buf == NULL)
				return;
			goto send_resp;
		}

		buf = gas_serv_build_gas_resp_payload(hapd,
						      dialog->all_requested,
						      dialog, NULL, 0);
		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
			buf);
		if (!buf)
			goto rx_gas_comeback_req_done;
		dialog->sd_resp = buf;
		dialog->sd_resp_pos = 0;
	}
	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
	if (frag_len > hapd->gas_frag_limit) {
		frag_len = hapd->gas_frag_limit;
		more = 1;
	}
	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
		(unsigned int) frag_len);
	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
				dialog->sd_resp_pos, frag_len);
	if (buf == NULL) {
		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
			"buffer");
		goto rx_gas_comeback_req_done;
	}
	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
						  WLAN_STATUS_SUCCESS,
						  dialog->sd_frag_id,
						  more, 0, buf);
	wpabuf_free(buf);
	if (tx_buf == NULL)
		goto rx_gas_comeback_req_done;
	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
		"(frag_id %d more=%d frag_len=%d)",
		dialog->sd_frag_id, more, (int) frag_len);
	dialog->sd_frag_id++;
	dialog->sd_resp_pos += frag_len;

	if (more) {
		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
			"to be sent",
			(int) (wpabuf_len(dialog->sd_resp) -
			       dialog->sd_resp_pos));
	} else {
		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
			"SD response sent");
		gas_serv_dialog_clear(dialog);
		gas_serv_free_dialogs(hapd, sa);
	}

send_resp:
	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
	wpabuf_free(tx_buf);
	return;

rx_gas_comeback_req_done:
	gas_serv_clear_cached_ies(dialog, NULL);
}
Beispiel #24
0
/**
 * eapol_sm_rx_eapol - Process received EAPOL frames
 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
 * @src: Source MAC address of the EAPOL packet
 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
 * @len: Length of the EAPOL frame
 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
 * -1 failure
 */
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
		      size_t len)
{
	const struct ieee802_1x_hdr *hdr;
	const struct ieee802_1x_eapol_key *key;
	int data_len;
	int res = 1;
	size_t plen;

	if (sm == NULL)
		return 0;
	sm->dot1xSuppEapolFramesRx++;
	if (len < sizeof(*hdr)) {
		sm->dot1xSuppInvalidEapolFramesRx++;
		return 0;
	}
	hdr = (const struct ieee802_1x_hdr *) buf;
	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
	if (hdr->version < EAPOL_VERSION) {
		/* TODO: backwards compatibility */
	}
	plen = be_to_host16(hdr->length);
	if (plen > len - sizeof(*hdr)) {
		sm->dot1xSuppEapLengthErrorFramesRx++;
		return 0;
	}
#ifdef CONFIG_WPS
	if (sm->conf.workaround &&
	    plen < len - sizeof(*hdr) &&
	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
		const struct eap_hdr *ehdr =
			(const struct eap_hdr *) (hdr + 1);
		u16 elen;

		elen = be_to_host16(ehdr->length);
		if (elen > plen && elen <= len - sizeof(*hdr)) {
			/*
			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
			 * packets with too short EAPOL header length field
			 * (14 octets). This is fixed in firmware Ver.1.49.
			 * As a workaround, fix the EAPOL header based on the
			 * correct length in the EAP packet.
			 */
			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
				   "payload length based on EAP header: "
				   "%d -> %d", (int) plen, elen);
			plen = elen;
		}
	}
#endif /* CONFIG_WPS */
	data_len = plen + sizeof(*hdr);

	switch (hdr->type) {
	case IEEE802_1X_TYPE_EAP_PACKET:
		if (sm->cached_pmk) {
			/* Trying to use PMKSA caching, but Authenticator did
			 * not seem to have a matching entry. Need to restart
			 * EAPOL state machines.
			 */
			eapol_sm_abort_cached(sm);
		}
		wpabuf_free(sm->eapReqData);
		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
		if (sm->eapReqData) {
			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
				   "frame");
			sm->eapolEap = TRUE;
			eapol_sm_step(sm);
		}
		break;
	case IEEE802_1X_TYPE_EAPOL_KEY:
		if (plen < sizeof(*key)) {
			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
				   "frame received");
			break;
		}
		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
		if (key->type == EAPOL_KEY_TYPE_WPA ||
		    key->type == EAPOL_KEY_TYPE_RSN) {
			/* WPA Supplicant takes care of this frame. */
			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
				   "frame in EAPOL state machines");
			res = 0;
			break;
		}
		if (key->type != EAPOL_KEY_TYPE_RC4) {
			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
				   "EAPOL-Key type %d", key->type);
			break;
		}
		os_free(sm->last_rx_key);
		sm->last_rx_key = os_malloc(data_len);
		if (sm->last_rx_key) {
			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
				   "frame");
			os_memcpy(sm->last_rx_key, buf, data_len);
			sm->last_rx_key_len = data_len;
			sm->rxKey = TRUE;
			eapol_sm_step(sm);
		}
		break;
	default:
		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
			   hdr->type);
		sm->dot1xSuppInvalidEapolFramesRx++;
		break;
	}

	return res;
}
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
			u16 status_code, const u8 *data, size_t len)
{
	int *groups;

	wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
		"status code %u", auth_transaction, status_code);

	if (auth_transaction == 1 &&
	    status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
	    wpa_s->sme.sae.state == SAE_COMMITTED &&
	    wpa_s->current_bss && wpa_s->current_ssid) {
		int default_groups[] = { 19, 20, 21, 25, 26, 0 };
		u16 group;

		groups = wpa_s->conf->sae_groups;
		if (!groups || groups[0] <= 0)
			groups = default_groups;

		if (len < sizeof(le16)) {
			wpa_dbg(wpa_s, MSG_DEBUG,
				"SME: Too short SAE anti-clogging token request");
			return -1;
		}
		group = WPA_GET_LE16(data);
		wpa_dbg(wpa_s, MSG_DEBUG,
			"SME: SAE anti-clogging token requested (group %u)",
			group);
		if (sae_group_allowed(&wpa_s->sme.sae, groups, group) !=
		    WLAN_STATUS_SUCCESS) {
			wpa_dbg(wpa_s, MSG_ERROR,
				"SME: SAE group %u of anti-clogging request is invalid",
				group);
			return -1;
		}
		wpabuf_free(wpa_s->sme.sae_token);
		wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
							 len - sizeof(le16));
		sme_send_authentication(wpa_s, wpa_s->current_bss,
					wpa_s->current_ssid, 1);
		return 0;
	}

	if (auth_transaction == 1 &&
	    status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED &&
	    wpa_s->sme.sae.state == SAE_COMMITTED &&
	    wpa_s->current_bss && wpa_s->current_ssid) {
		wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
		wpa_s->sme.sae_group_index++;
		if (sme_set_sae_group(wpa_s) < 0)
			return -1; /* no other groups enabled */
		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group");
		sme_send_authentication(wpa_s, wpa_s->current_bss,
					wpa_s->current_ssid, 1);
		return 0;
	}

	if (status_code != WLAN_STATUS_SUCCESS)
		return -1;

	if (auth_transaction == 1) {
		groups = wpa_s->conf->sae_groups;

		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
		if (wpa_s->current_bss == NULL ||
		    wpa_s->current_ssid == NULL)
			return -1;
		if (wpa_s->sme.sae.state != SAE_COMMITTED)
			return -1;
		if (groups && groups[0] <= 0)
			groups = NULL;
		if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
				     groups) != WLAN_STATUS_SUCCESS)
			return -1;

		if (sae_process_commit(&wpa_s->sme.sae) < 0) {
			wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
				   "commit");
			return -1;
		}

		wpabuf_free(wpa_s->sme.sae_token);
		wpa_s->sme.sae_token = NULL;
		sme_send_authentication(wpa_s, wpa_s->current_bss,
					wpa_s->current_ssid, 0);
		return 0;
	} else if (auth_transaction == 2) {
		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
		if (wpa_s->sme.sae.state != SAE_CONFIRMED)
			return -1;
		if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0)
			return -1;
		wpa_s->sme.sae.state = SAE_ACCEPTED;
		sae_clear_temp_data(&wpa_s->sme.sae);
		return 1;
	}

	return -1;
}
Beispiel #26
0
/**
 * radius_msg_parse - Parse a RADIUS message
 * @data: RADIUS message to be parsed
 * @len: Length of data buffer in octets
 * Returns: Parsed RADIUS message or %NULL on failure
 *
 * This parses a RADIUS message and makes a copy of its data. The caller is
 * responsible for freeing the returned data with radius_msg_free().
 */
struct radius_msg * radius_msg_parse(const u8 *data, size_t len)
{
	struct radius_msg *msg;
	struct radius_hdr *hdr;
	struct radius_attr_hdr *attr;
	size_t msg_len;
	unsigned char *pos, *end;

	if (data == NULL || len < sizeof(*hdr))
		return NULL;

	hdr = (struct radius_hdr *) data;

	msg_len = ntohs(hdr->length);
	if (msg_len < sizeof(*hdr) || msg_len > len) {
		wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
		return NULL;
	}

	if (msg_len < len) {
		wpa_printf(MSG_DEBUG, "RADIUS: Ignored %lu extra bytes after "
			   "RADIUS message", (unsigned long) len - msg_len);
	}

	msg = os_zalloc(sizeof(*msg));
	if (msg == NULL)
		return NULL;

	msg->buf = wpabuf_alloc_copy(data, msg_len);
	if (msg->buf == NULL || radius_msg_initialize(msg)) {
		radius_msg_free(msg);
		return NULL;
	}
	msg->hdr = wpabuf_mhead(msg->buf);

	/* parse attributes */
	pos = wpabuf_mhead_u8(msg->buf) + sizeof(struct radius_hdr);
	end = wpabuf_mhead_u8(msg->buf) + wpabuf_len(msg->buf);
	while (pos < end) {
		if ((size_t) (end - pos) < sizeof(*attr))
			goto fail;

		attr = (struct radius_attr_hdr *) pos;

		if (pos + attr->length > end || attr->length < sizeof(*attr))
			goto fail;

		/* TODO: check that attr->length is suitable for attr->type */

		if (radius_msg_add_attr_to_array(msg, attr))
			goto fail;

		pos += attr->length;
	}

	return msg;

 fail:
	radius_msg_free(msg);
	return NULL;
}
Beispiel #27
0
void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
			      struct gas_dialog_info *dialog)
{
	struct wpabuf *buf, *tx_buf;
	u8 dialog_token = dialog->dialog_token;
	size_t frag_len;

	if (dialog->sd_resp == NULL) {
		buf = gas_serv_build_gas_resp_payload(hapd,
						      dialog->all_requested,
						      dialog, NULL, 0);
		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
			buf);
		if (!buf)
			goto tx_gas_response_done;
		dialog->sd_resp = buf;
		dialog->sd_resp_pos = 0;
	}
	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
	if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
	    hapd->conf->gas_comeback_delay) {
		u16 comeback_delay_tus = dialog->comeback_delay +
			GAS_SERV_COMEBACK_DELAY_FUDGE;
		u32 comeback_delay_secs, comeback_delay_usecs;

		if (hapd->conf->gas_comeback_delay) {
			/* Testing - allow overriding of the delay value */
			comeback_delay_tus = hapd->conf->gas_comeback_delay;
		}

		wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
			   "%u) and comeback delay %u, "
			   "requesting comebacks", (unsigned int) frag_len,
			   (unsigned int) hapd->gas_frag_limit,
			   dialog->comeback_delay);
		tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
							 WLAN_STATUS_SUCCESS,
							 comeback_delay_tus,
							 NULL);
		if (tx_buf) {
			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
						dst,
						wpabuf_head(tx_buf),
						wpabuf_len(tx_buf));
		}
		wpabuf_free(tx_buf);

		/* start a timer of 1.5 * comeback-delay */
		comeback_delay_tus = comeback_delay_tus +
			(comeback_delay_tus / 2);
		comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
		comeback_delay_usecs = (comeback_delay_tus * 1024) -
			(comeback_delay_secs * 1000000);
		eloop_register_timeout(comeback_delay_secs,
				       comeback_delay_usecs,
				       gas_serv_clear_cached_ies, dialog,
				       NULL);
		goto tx_gas_response_done;
	}

	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
				dialog->sd_resp_pos, frag_len);
	if (buf == NULL) {
		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
			"failed");
		goto tx_gas_response_done;
	}
	tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
						 WLAN_STATUS_SUCCESS, 0, buf);
	wpabuf_free(buf);
	if (tx_buf == NULL)
		goto tx_gas_response_done;
	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
		"Response (frag_id %d frag_len %d)",
		dialog->sd_frag_id, (int) frag_len);
	dialog->sd_frag_id++;

	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
	wpabuf_free(tx_buf);
tx_gas_response_done:
	gas_serv_clear_cached_ies(dialog, NULL);
}
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;
}
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
				  struct wpa_bss *bss, const u8 *sa,
				  const u8 *data, size_t slen, u8 dialog_token)
{
	const u8 *pos = data;
	u8 subtype;
	struct wpa_bss_anqp *anqp = NULL;
	int ret;

	if (slen < 2)
		return;

	if (bss)
		anqp = bss->anqp;

	subtype = *pos++;
	slen--;

	pos++; /* Reserved */
	slen--;

	switch (subtype) {
	case HS20_STYPE_CAPABILITY_LIST:
		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
			" HS Capability List", MAC2STR(sa));
		wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
		if (anqp) {
			wpabuf_free(anqp->hs20_capability_list);
			anqp->hs20_capability_list =
				wpabuf_alloc_copy(pos, slen);
		}
		break;
	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
			" Operator Friendly Name", MAC2STR(sa));
		wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
		if (anqp) {
			wpabuf_free(anqp->hs20_operator_friendly_name);
			anqp->hs20_operator_friendly_name =
				wpabuf_alloc_copy(pos, slen);
		}
		break;
	case HS20_STYPE_WAN_METRICS:
		wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen);
		if (slen < 13) {
			wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN "
				"Metrics value from " MACSTR, MAC2STR(sa));
			break;
		}
		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
			" WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
			pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
			pos[9], pos[10], WPA_GET_LE16(pos + 11));
		if (anqp) {
			wpabuf_free(anqp->hs20_wan_metrics);
			anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
		}
		break;
	case HS20_STYPE_CONNECTION_CAPABILITY:
		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
			" Connection Capability", MAC2STR(sa));
		wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
		if (anqp) {
			wpabuf_free(anqp->hs20_connection_capability);
			anqp->hs20_connection_capability =
				wpabuf_alloc_copy(pos, slen);
		}
		break;
	case HS20_STYPE_OPERATING_CLASS:
		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
			" Operating Class", MAC2STR(sa));
		wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
		if (anqp) {
			wpabuf_free(anqp->hs20_operating_class);
			anqp->hs20_operating_class =
				wpabuf_alloc_copy(pos, slen);
		}
		break;
	case HS20_STYPE_OSU_PROVIDERS_LIST:
		wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
			" OSU Providers list", MAC2STR(sa));
		wpa_s->num_prov_found++;
		if (anqp) {
			wpabuf_free(anqp->hs20_osu_providers_list);
			anqp->hs20_osu_providers_list =
				wpabuf_alloc_copy(pos, slen);
		}
		break;
	case HS20_STYPE_ICON_BINARY_FILE:
		ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen,
						    dialog_token);
		if (wpa_s->fetch_osu_icon_in_progress) {
			hs20_osu_icon_fetch_result(wpa_s, ret);
			eloop_cancel_timeout(hs20_continue_icon_fetch,
					     wpa_s, NULL);
			eloop_register_timeout(0, 0, hs20_continue_icon_fetch,
					       wpa_s, NULL);
		}
		break;
	default:
		wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
		break;
	}
}
struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
		 int flags, const struct wpabuf *assoc_wps_ie,
		 const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
		 const char *identity, const char *radius_cui)
{
	struct eapol_state_machine *sm;
	struct eap_config eap_conf;

	if (eapol == NULL)
		return NULL;

	sm = os_zalloc(sizeof(*sm));
	if (sm == NULL) {
		wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
			   "failed");
		return NULL;
	}
	sm->radius_identifier = -1;
	os_memcpy(sm->addr, addr, ETH_ALEN);
	sm->flags = flags;

	sm->eapol = eapol;
	sm->sta = sta_ctx;

	/* Set default values for state machine constants */
	sm->auth_pae_state = AUTH_PAE_INITIALIZE;
	sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
	sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;

	sm->be_auth_state = BE_AUTH_INITIALIZE;
	sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;

	sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
	sm->reAuthPeriod = eapol->conf.eap_reauth_period;
	sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;

	sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;

	sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;

	sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;

	sm->portControl = Auto;

	if (!eapol->conf.wpa &&
	    (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
		sm->keyTxEnabled = TRUE;
	else
		sm->keyTxEnabled = FALSE;
	if (eapol->conf.wpa)
		sm->portValid = FALSE;
	else
		sm->portValid = TRUE;

	os_memset(&eap_conf, 0, sizeof(eap_conf));
	eap_conf.eap_server = eapol->conf.eap_server;
	eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
	eap_conf.msg_ctx = eapol->conf.msg_ctx;
	eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
	eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
	eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
	eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
	eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
	eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
	eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
	eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
	eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
	eap_conf.tnc = eapol->conf.tnc;
	eap_conf.wps = eapol->conf.wps;
	eap_conf.assoc_wps_ie = assoc_wps_ie;
	eap_conf.assoc_p2p_ie = assoc_p2p_ie;
	eap_conf.peer_addr = addr;
	eap_conf.fragment_size = eapol->conf.fragment_size;
	eap_conf.pwd_group = eapol->conf.pwd_group;
	eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
	eap_conf.server_id = eapol->conf.server_id;
	eap_conf.server_id_len = eapol->conf.server_id_len;
	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
	if (sm->eap == NULL) {
		eapol_auth_free(sm);
		return NULL;
	}
	sm->eap_if = eap_get_interface(sm->eap);

	eapol_auth_initialize(sm);

	if (identity) {
		sm->identity = (u8 *) os_strdup(identity);
		if (sm->identity)
			sm->identity_len = os_strlen(identity);
	}
	if (radius_cui)
		sm->radius_cui = wpabuf_alloc_copy(radius_cui,
						   os_strlen(radius_cui));

	return sm;
}