Esempio n. 1
0
static void
ap_eap_sm_sendEap(char *eap_data, unsigned short eap_len)
{
	WpsEapHdr *fwpsEapHdr = (WpsEapHdr *)eap_data;
	uint8 *fwpsEapHdrLF = (uint8 *)(fwpsEapHdr + 1);
	unsigned short wps_len = eap_len - sizeof(WpsEapHdr);

	/* No fragmentation need, shift EAP_WPS_LF_OFFSET */
	if (wps_len <= apEapState->eap_frag_threshold) {
		ap_eap_sm_sendEapol(&apEapState->msg_to_send[EAP_WPS_LF_OFFSET],
			eap_data, eap_len);
		return;
	}

	/* Modify FIRST fragmentation */
	fwpsEapHdr->flags = (EAP_WPS_FLAGS_MF | EAP_WPS_FLAGS_LF);
	fwpsEapHdr->length = WpsHtons(sizeof(WpsEapHdr) + apEapState->eap_frag_threshold);

	/* Set WPS data length field */
	WpsHtonsPtr((uint8*)&wps_len, (uint8*)fwpsEapHdrLF);

	/* Set next_frag_to_send to first WpsEapHdr to indecate first fragmentation has sent */
	apEapState->next_frag_to_send = &apEapState->msg_to_send[EAPOL_HEADER_LEN];

	/* frag_szie only save wps_len */
	apEapState->frag_size = wps_len;

	ap_eap_sm_sendEapol(apEapState->msg_to_send, (char *)fwpsEapHdr,
		WpsNtohs((uint8 *)&fwpsEapHdr->length));
}
Esempio n. 2
0
/* Send one fragmented packet. */
static void
ap_eap_sm_sendNextFrag(WpsEapHdr *wpsEapHdr)
{
	eapol_header_t *feapolHdr = NULL;
	WpsEapHdr *fwpsEapHdr = NULL;
	uint8 flags = 0;
	int max_to_send = apEapState->eap_frag_threshold;


	/* Locate EAPOL and EAP header */
	feapolHdr = (eapol_header_t *)(apEapState->next_frag_to_send - WPS_DATA_OFFSET);
	fwpsEapHdr = (WpsEapHdr *)feapolHdr->body;

	/* How maximum length to send */
	if (apEapState->frag_size < apEapState->eap_frag_threshold)
		max_to_send = apEapState->frag_size;

	/* More fragmentations check */
	if (apEapState->frag_size > max_to_send)
		flags = EAP_WPS_FLAGS_MF;

	/* Create one fragmentation */
	*fwpsEapHdr = *wpsEapHdr;
	fwpsEapHdr->id = apEapState->eap_id;
	fwpsEapHdr->flags = flags;
	fwpsEapHdr->length = WpsHtons(sizeof(WpsEapHdr) + max_to_send);

	ap_eap_sm_sendEapol((char *)feapolHdr, (char *)fwpsEapHdr,
		WpsNtohs((uint8 *)&fwpsEapHdr->length));
}
Esempio n. 3
0
uint32
ap_eap_sm_sendMsg(char *dataBuffer, uint32 dataLen)
{
	uint32 retVal;
	eapol_header_t *eapolHdr = (eapol_header_t *)apEapState->msg_to_send;
	WpsEapHdr *wpsEapHdr;

	TUTRACE((TUTRACE_INFO, "In ap_eap_sm_sendMsg buffer Length = %d\n",
		dataLen));

	retVal = ap_eap_sm_create_pkt(dataBuffer, dataLen, EAP_CODE_REQUEST);
	if (retVal == WPS_SUCCESS) {
		/* Shift EAP_WPS_LF_OFFSET */
		if (dataLen < apEapState->eap_frag_threshold)
			eapolHdr = (eapol_header_t *)&apEapState->msg_to_send[EAP_WPS_LF_OFFSET];

		wpsEapHdr = (WpsEapHdr *)eapolHdr->body;
		ap_eap_sm_sendEap((char *)wpsEapHdr, WpsNtohs((uint8*)&wpsEapHdr->length));
		apEapState->state = PROCESSING_PROTOCOL;
	}
	else {
		TUTRACE((TUTRACE_ERR,  "Send EAP FAILURE to station!\n"));
		ap_eap_sm_Failure(apEap_wps_version2 ? 1 : 0);

		retVal = TREAP_ERR_SENDRECV;
	}

	return retVal;
}
Esempio n. 4
0
/*
 * Receive a fragmentation then send EAP_FRAG_ACK.
 */
static int
ap_eap_sm_process_frag(char *eap_msg)
{
	int ret;
	int LF_bytes = 0;
	WpsEapHdr *wpsEapHdr = (WpsEapHdr *)eap_msg;
	uint32 wps_len = WpsNtohs((uint8*)&wpsEapHdr->length) - sizeof(WpsEapHdr);
	int wps_data_received = apEapState->total_received - sizeof(WpsEapHdr);


	TUTRACE((TUTRACE_INFO, "Receive a EAP WPS fragment packet\n"));

	/* Total length checking */
	if (apEapState->total_bytes_to_recv < wps_data_received + wps_len) {
		TUTRACE((TUTRACE_ERR, "Received WPS data len %d excess total bytes to "
			"receive %d\n", wps_data_received + wps_len,
			apEapState->total_bytes_to_recv));
		return EAP_FAILURE;
	}

	/* Copy to frags_received */
	/* First fragmentation include WpsEapHdr without length field */
	if (apEapState->total_received == 0) {
		memcpy(apEapState->frags_received, eap_msg, sizeof(WpsEapHdr));
		apEapState->total_received += sizeof(WpsEapHdr);

		/* Ignore length field 2 bytes copy */
		LF_bytes = EAP_WPS_LF_OFFSET;
	}
	/* WPS data */
	memcpy(&apEapState->frags_received[apEapState->total_received],
		eap_msg + sizeof(WpsEapHdr) + LF_bytes,	wps_len - LF_bytes);
	apEapState->total_received += wps_len - LF_bytes;

	/* Is last framentation? */
	if (wpsEapHdr->flags & EAP_WPS_FLAGS_MF) {
		/* Increase eap_id */
		apEapState->eap_id++;

		/* Send WPS_FRAG_ACK */
		ret = ap_eap_sm_sendFACK();
		if (ret == WPS_SUCCESS)
			return WPS_CONT;

		return ret;
	}

	/* Got all fragmentations, adjust WpsEapHdr */
	wpsEapHdr = (WpsEapHdr *)apEapState->frags_received;
	wpsEapHdr->length = WpsHtons((uint16)apEapState->total_received);

	TUTRACE((TUTRACE_ERR, "Received all WPS fragmentations, total bytes of WPS data "
		"to receive %d, received %d\n", apEapState->total_bytes_to_recv,
		apEapState->total_received - sizeof(WpsEapHdr)));

	return WPS_SUCCESS;
}
Esempio n. 5
0
static uint32
ap_eap_sm_sta_validate(char *eapol_msg)
{
	eapol_header_t *eapolHdr = (eapol_header_t *) eapol_msg;
	WpsEapHdr * wpsEapHdr = (WpsEapHdr *) eapolHdr->body;
	unsigned char *mac;

	/* Ignore non 802.1x EAP BRCM packets (dont error) */
	if (WpsNtohs((uint8*)&eapolHdr->eth.ether_type) != ETHER_TYPE_802_1X)
		return WPS_ERR_GENERIC;

	/* Ignore EAPOL_LOGOFF */
	if (eapolHdr->type == EAPOL_LOGOFF) {
		return WPS_CONT;
	}

	if ((WpsNtohs((uint8*)&eapolHdr->length) <= EAP_HEADER_LEN) ||
		(eapolHdr->type != EAP_PACKET) ||
		((wpsEapHdr->type != EAP_EXPANDED) && (wpsEapHdr->type != EAP_IDENTITY))) {
		return WPS_ERR_GENERIC;
	}

	mac = lookupSta(eapolHdr->eth.ether_shost, SEARCH_ONLY);
	if ((wpsEapHdr->type == EAP_IDENTITY) && mac) {
		if (memcmp(eapolHdr->eth.ether_shost, mac, ETHER_ADDR_LEN)) {
			TUTRACE((TUTRACE_ERR,  "Other sta's EAP_IDENTITY comes, ignore it...\n"));
			return WPS_CONT;
		}
		else {
			TUTRACE((TUTRACE_ERR,  "EAP_IDENTITY comes again...\n"));
		}
	}

	mac = lookupSta(eapolHdr->eth.ether_shost, SEARCH_ENTER);
	if (!mac) {
		TUTRACE((TUTRACE_ERR,  "no sta...\n"));
		return WPS_ERR_GENERIC;
	}

	return WPS_SUCCESS;
}
Esempio n. 6
0
uint32
reg_proto_check_nonce(IN uint8 *nonce, IN BufferObj *msg, IN int nonceType)
{
	uint16 type;

	if ((nonceType != WPS_ID_REGISTRAR_NONCE) &&
		(nonceType !=  WPS_ID_ENROLLEE_NONCE)) {
		TUTRACE((TUTRACE_ERR, "RPROTO: Invalid attribute ID passed to"
			" CheckNonce\n"));
		return WPS_ERR_INVALID_PARAMETERS;
	}

	while (1) {
		type = buffobj_NextType(msg);
		if (!type)
			break;
		if (nonceType == type) {
			if (!(memcmp(nonce, msg->pCurrent+sizeof(WpsTlvHdr),
				SIZE_128_BITS))) {
				buffobj_Rewind(msg);
				return WPS_SUCCESS;
			}
			else {
				TUTRACE((TUTRACE_ERR, "RPROTO: Nonce mismatch\n"));
				buffobj_Rewind(msg);
				return RPROT_ERR_NONCE_MISMATCH;
			}
		}

		/*
		 * advance past the TLV - the total number of bytes to advance is
		 * the size of the TLV header + the length indicated in the header
		 */
		if (!(buffobj_Advance(msg, sizeof(WpsTlvHdr) +
			WpsNtohs((msg->pCurrent+sizeof(uint16)))))) {
			TUTRACE((TUTRACE_ERR, "RPROTO: Didn't find nonce\n"));
			break;
		 }
	}

	buffobj_Rewind(msg);
	return RPROT_ERR_REQD_TLV_MISSING;
}
Esempio n. 7
0
static int
ap_eap_sm_process_protocol(char *eap_msg)
{
	WpsEapHdr *wpsEapHdr = (WpsEapHdr *)eap_msg;
	char *in_data = (char *)(wpsEapHdr + 1);
	uint32 in_len = WpsNtohs((uint8*)&wpsEapHdr->length) - sizeof(WpsEapHdr);

	/* record the in message id, ingore WPS_Start */
	if (wpsEapHdr->opcode != WPS_Start) {
		apEapState->recv_msg_id = in_data[WPS_MSGTYPE_OFFSET];
		if (apEapState->recv_msg_id == WPS_ID_MESSAGE_M1)
			apEapState->flags |= AP_EAP_SM_M1_RECVD;
	}

	/* reset msg_len, shift EAP_WPS_LF_OFFSET */
	apEapState->msg_len = sizeof(apEapState->msg_to_send) - WPS_DATA_OFFSET
		- EAP_WPS_LF_OFFSET;
	return wps_processMsg(apEapState->mc_dev, in_data, in_len,
		&apEapState->msg_to_send[WPS_DATA_OFFSET + EAP_WPS_LF_OFFSET],
		(uint32 *)&apEapState->msg_len, TRANSPORT_TYPE_EAP);
}
Esempio n. 8
0
uint32
ap_eap_sm_process_sta_msg(char *msg, int msg_len)
{
	eapol_header_t *eapolHdr = NULL;
	WpsEapHdr *wpsEapHdr = NULL;
	int len;
	int wps_data_sent_bytes = apEapState->eap_frag_threshold;
	int advance_bytes = apEapState->eap_frag_threshold;
	int wps_eap_id;
	char *total_bytes_to_recv;
	WPS_SCMODE e_mode;
	uint32 ret;


	/* Check initialization */
	if (apEapState == 0)
		return WPS_MESSAGE_PROCESSING_ERROR;

	if (apEapState->parse_msg)
		eapolHdr = (eapol_header_t *) (*apEapState->parse_msg)(msg, msg_len, &len);

	if (!eapolHdr) {
		TUTRACE((TUTRACE_ERR,  "Missing EAPOL header\n"));
		return WPS_ERR_GENERIC;
	}

	/* Validate eapol message */
	if ((ret = ap_eap_sm_sta_validate((char*)eapolHdr)) != WPS_SUCCESS) {
		TUTRACE((TUTRACE_ERR,  "Vaildation failed...\n"));
		return ret;
	}

	/* Reset resend count   */
	apEapState->resent_count = 0;

	/*
	 * Handle same station eap identity response comes again:
	 * 1. When AP is a enrollee, we have to take care of same station eap identity response
	 *     comes again change to "WFA-SimpleConfig-Enrollee-1-0"
	 * 2. When AP is a registrar, we have to take care of same station eap identity response
	 *     comes again change to "WFA-SimpleConfig-Registrar-1-0"
	 */
	wpsEapHdr = (WpsEapHdr *)eapolHdr->body;
	if (wpsEapHdr->type == EAP_TYPE_IDENTITY) {

		wps_eap_id = ap_eap_sm_get_wpsid(msg);
		/* Ignore unrecognized WPS eap id */
		if (wps_eap_id == AP_EAP_WPS_ID_NONE)
			return WPS_CONT;

		e_mode = wps_get_mode(apEapState->mc_dev);
		/* Case 1, AP is running as Enrollee send EAP-Request(M1) */
		if (e_mode == SCMODE_AP_ENROLLEE) {
			/* Peer switch to Enrollee comes again */
			if (wps_eap_id == AP_EAP_WPS_ID_ENROLLEE) {
				TUTRACE((TUTRACE_INFO, "We are running as Enrollee but comes "
					"again EAP Identity Response changes to WFA-SimpleConfig-"
					"Enrollee-1-0. Return ERROR and close session!\n"));
				return WPS_MESSAGE_PROCESSING_ERROR;

			}
			/* Registrar comes again */
			else if (apEapState->sent_msg_id == WPS_ID_MESSAGE_M1) {
				/* Re-send last sent message */
				ap_eap_sm_resend_last_sent();
				return WPS_CONT;
			}
		}
		/* Case 2, AP is running as Registrar send EAP-Request(Start) */
		else if (e_mode == SCMODE_AP_REGISTRAR) {
			/* Peer switch to Registrar comes again */
			if (wps_eap_id == AP_EAP_WPS_ID_REGISTRAR) {
				TUTRACE((TUTRACE_INFO, "We are running as Registrar but comes "
					"again EAP Identity Response changes to WFA-SimpleConfig-"
					"Registrar-1-0. Return ERROR and close session!\n"));
				return WPS_MESSAGE_PROCESSING_ERROR;
			}
			/* Enrollee comes again */
			else if (apEapState->state == EAP_START_SEND) {
				/* Re-send last sent message */
				ap_eap_sm_resend_last_sent();
				return WPS_CONT;
			}
		}
	}

	/* STA retransmission checking */
	ret = ap_eap_sm_sta_retrans((char*)eapolHdr);
	if (ret != WPS_SEND_RET_MSG_CONT && ret != WPS_CONT) {
		if (ret == WPS_IGNORE_MSG_CONT)
			ret = WPS_CONT;
		return ret;
	}
	else if (ret == WPS_SEND_RET_MSG_CONT) {
		/* Re-send last sent message */
		ap_eap_sm_resend_last_sent();
		return WPS_CONT;
	}

	/*
	 * For Fragmentation: Test if we are waiting for a WPS_FRAG_ACK
	 * If so, only accept that code and send the next fragment directly
	 * with ap_eap_sm_sendNextFrag().  Return with no error.
	 */
	if (IS_EAP_TYPE_WPS(wpsEapHdr) && FRAGMENTING(apEapState)) {
		/* Only accept WPS_FRAG_ACK and send next fragmentation */
		if (wpsEapHdr->opcode == WPS_FRAG_ACK) {
			TUTRACE((TUTRACE_INFO, "Receive a WPS fragment ACK packet, send next\n"));

			/* Is first WPS_FRAG_ACK? */
			if (apEapState->next_frag_to_send ==
				&apEapState->msg_to_send[EAPOL_HEADER_LEN]) {
				wps_data_sent_bytes -= EAP_WPS_LF_OFFSET;
				advance_bytes += sizeof(WpsEapHdr);
			}

			/* Advance to next fragment point */
			apEapState->next_frag_to_send += advance_bytes;
			apEapState->frag_size -= wps_data_sent_bytes;
			apEapState->eap_id++;

			/* Get msg_to_send WpsEapHdr */
			eapolHdr = (eapol_header_t *)apEapState->msg_to_send;
			wpsEapHdr = (WpsEapHdr *)eapolHdr->body;

			/* Send next fragmented packet */
			ap_eap_sm_sendNextFrag(wpsEapHdr);

			return WPS_CONT;
		}
		/* Bypass non WPS_MSG */
		else if (wpsEapHdr->opcode == WPS_MSG) {
			if (apEapState->frag_size < apEapState->eap_frag_threshold) {
				/* All fragmentations sent completed, reset next_frag_to_send */
				apEapState->next_frag_to_send = apEapState->msg_to_send;
				apEapState->frag_size = 0;
				/* Fall through, process this message. */
			} else {
				TUTRACE((TUTRACE_INFO, "Not a WPS_FRAG_ACK packet, ingore it\n"));
				return WPS_CONT;
			}
		}
	}

	/* For reassembly: Test if this is a fragmented packet.
	 * If it is the begining, set the expected total.
	 * Copy new data at position (frags_received  + total_received) and increase total_received.
	 * Make sure to detect re-transmissions (same ID)?.
	 * When receiving a packet without the "More Fragment" flags,
	 * continue, otherwise send a WPS_FRAG_ACK with ap_eap_sm_sendFACK() and return;
	 */
	total_bytes_to_recv = (char *)(wpsEapHdr + 1);
	if (IS_EAP_TYPE_WPS(wpsEapHdr) && REASSEMBLING(apEapState, wpsEapHdr)) {
		if (apEapState->total_bytes_to_recv == 0) {
			/* First fragmentation must have length information */
			if (!(wpsEapHdr->flags & EAP_WPS_FLAGS_LF)) {
				return EAP_FAILURE;
			}

			/* Save total EAP message length */
			apEapState->total_bytes_to_recv = WpsNtohs((uint8*)total_bytes_to_recv);
			TUTRACE((TUTRACE_INFO, "Got EAP WPS total bytes to receive info %d\n",
				apEapState->total_bytes_to_recv));
		}

		ret = ap_eap_sm_process_frag((char *)wpsEapHdr);
		if (ret != WPS_SUCCESS)
			return ret;

		/* fall through when all fragmentations are received. */
		apEapState->total_received = 0; /* Reset total_received */
		apEapState->total_bytes_to_recv = 0;

		/* Use reassembled buffer */
		wpsEapHdr = (WpsEapHdr *)apEapState->frags_received;
	}

	switch (apEapState->state) {
		case INIT :
			/* Reset counter  */
			apEapState->eap_id = 1;

			/* Request Start message */
			return ap_eap_sm_req_start();

		case EAP_START_SEND:
		case PROCESSING_PROTOCOL:
			apEapState->eap_id++;

			ret = ap_eap_sm_process_protocol((char *)wpsEapHdr);

			/* For DTM WCN Wireless ID 463. M1-M2D Proxy Functionality */
			if (ret == WPS_AP_M2D_READY_CONT)
				ret = ap_eap_sm_apm2d_alloc();
			return ret;

		case REG_SUCCESSFUL:
			return REG_SUCCESSFUL;
	}

	return WPS_CONT;
}
Esempio n. 9
0
/*
 * Check if we already have requested and our peer didn't receive it.
 * Also check that that the id matches the response. AP dependent.
 */
static uint32
ap_eap_sm_sta_retrans(char *eapol_msg)
{
	char *wps_data;
	eapol_header_t *eapolHdr = (eapol_header_t *) eapol_msg;
	WpsEapHdr * wpsEapHdr = (WpsEapHdr *) eapolHdr->body;


	/* Re-ransmissions detection, fragmenting /Reassembling checking */
	if (IS_EAP_TYPE_WPS(wpsEapHdr) &&
	    (FRAGMENTING(apEapState) || REASSEMBLING(apEapState, wpsEapHdr))) {
		if (wpsEapHdr->id == apEapState->eap_id - 1) {
			TUTRACE((TUTRACE_INFO, "wpsEapHdr->id=%d, apEapState->eap_id=%d\n",
				wpsEapHdr->id, apEapState->eap_id));
			TUTRACE((TUTRACE_INFO, "Peer's retransmission of previous messages(FRAG)"
				", ignore it\n"));
			return WPS_IGNORE_MSG_CONT;
		}

		return WPS_CONT;
	}

	switch (apEapState->state) {
	case INIT :
		if (wpsEapHdr->type != EAP_TYPE_IDENTITY)
			return WPS_ERR_GENERIC;

		if (wpsEapHdr->id != apEapState->eap_id ||
			wpsEapHdr->code != EAP_CODE_RESPONSE) {
			TUTRACE((TUTRACE_ERR,  "bogus EAP packet id %d code %d, "
				"expected %d\n", wpsEapHdr->id, wpsEapHdr->code,
				apEapState->eap_id));
			cleanUpSta(DOT11_RC_8021X_AUTH_FAIL, 1);
			return WPS_ERR_GENERIC;
		}

		TUTRACE((TUTRACE_ERR,  "Response, Identity, code=%d, id=%d, length=%d, type=%d\n",
			wpsEapHdr->code, wpsEapHdr->id,
			WpsNtohs((uint8*)&wpsEapHdr->length), wpsEapHdr->type));

		/* Store whcih if sta come from */
		memcpy(&apEapState->bssid, &eapolHdr->eth.ether_dhost, ETHER_ADDR_LEN);
		break;

	case EAP_START_SEND:
	case PROCESSING_PROTOCOL:
		if (wpsEapHdr->code != EAP_CODE_RESPONSE) {
			TUTRACE((TUTRACE_ERR,  "bogus EAP packet not response code %d\n",
				wpsEapHdr->code));
			cleanUpSta(DOT11_RC_8021X_AUTH_FAIL, 1);
			return WPS_ERR_GENERIC;
		}

		if (wpsEapHdr->id != apEapState->eap_id) {
			/*
			 * Ignore eap_id check in ACK message,
			 * When there are more than 2 ER, AP may receive
			 * ACK for M2D-1 after AP send M2D-2, in this case
			 * the M2D-1 and M2D-2 use same eap_id because
			 * eap_id increased by receiving peer eap packet.
			 * One other case AP receive M2D-1 and M2-2.
			 * Note; see WSC 2.0 spec figure 9.
			 */
			if (apEapState->sent_msg_id == WPS_ID_MESSAGE_M2 ||
			    apEapState->sent_msg_id == WPS_ID_MESSAGE_M2D) {
				if (wpsEapHdr->opcode == WPS_ACK)
					break; /* Ignore retrans */
				else if (wpsEapHdr->opcode == WPS_MSG) {
					wps_data = (char *)(wpsEapHdr + 1);
					if (wps_data[WPS_MSGTYPE_OFFSET] == WPS_ID_MESSAGE_M3)
						break; /* Ignore retrans */
				}
			}

			/*
			 * Do retransmission when comes messages with id = eap_id -1.
			 * They are probably retransmissions of previous messages.
			 */
			if (wpsEapHdr->id == apEapState->eap_id - 1) {
				TUTRACE((TUTRACE_INFO, "wpsEapHdr->id=%d, apEapState->eap_id=%d\n",
					wpsEapHdr->id, apEapState->eap_id));
				TUTRACE((TUTRACE_INFO, "Peer's retransmission of previous messages"
					",ignore it\n"));
				return WPS_IGNORE_MSG_CONT;
			}

			TUTRACE((TUTRACE_ERR,  "bogus EAP packet id %d, expected %d\n",
				wpsEapHdr->id, apEapState->eap_id));
			cleanUpSta(DOT11_RC_8021X_AUTH_FAIL, 1);
			return WPS_ERR_GENERIC;
		}
		break;
	}

	return WPS_CONT;
}