⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ieee802_1x.c

📁 Ralink RT61 SoftAP Driver source code. RT61:MiniPCI
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation. See README and COPYING for
 * more details.

	Module Name:
	ieee802_1x.c

	Revision History:
	Who 		When		  What
	--------	----------	  ----------------------------------------------
	Jan, Lee	Dec --2003	  modified

*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <assert.h>
#include <time.h>
#include <sys/time.h>
#include <sys/socket.h>

#include "rt61apd.h"
#include "ieee802_1x.h"
#include "radius.h"
#include "radius_client.h"
#include "eapol_sm.h"
#include "md5.h"
#include "eloop.h"
#include "sta_info.h"

static void ieee802_1x_send(rtapd *rtapd, struct sta_info *sta, u8 type, u8 *data, size_t datalen)
{
	char *buf;
	struct ieee8023_hdr *hdr3;
	struct ieee802_1x_hdr *xhdr;
	size_t len;
	u8 *pos;
		   
	len = sizeof(*hdr3) + 2+ sizeof(*xhdr) +datalen;
	buf = (char *) malloc(len);
	if (buf == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR,"malloc() failed for ieee802_1x_send(len=%d)\n", len);
		return;
	}
	DBGPRINT(RT_DEBUG_TRACE,"Send to Sta(ra%d) with Identifier %d\n",sta->ApIdx,*(data+1));
	memset(buf, 0, len);
	hdr3 = (struct ieee8023_hdr *) buf;
	memcpy(hdr3->dAddr, sta->addr, ETH_ALEN);
	memcpy(hdr3->sAddr, rtapd->own_addr[sta->ApIdx], ETH_ALEN);

	if (sta->ethertype == ETH_P_PRE_AUTH)
		(hdr3->eth_type) = htons(ETH_P_PRE_AUTH);
	else
		(hdr3->eth_type) = htons(ETH_P_PAE);

	pos = (u8 *) (hdr3 + 1);
	xhdr = (struct ieee802_1x_hdr *) pos;
	if (sta->ethertype == ETH_P_PRE_AUTH)
		xhdr->version = EAPOL_VERSION_2;
	else
		xhdr->version = EAPOL_VERSION;
	xhdr->type = type;
	xhdr->length = htons(datalen);

	if (datalen > 0 && data != NULL)
		memcpy(pos + LENGTH_8021X_HDR, data, datalen);

	//If (ethertype==ETH_P_PRE_AUTH), this means the packet is to or from ehternet socket(WPA2, pre-auth)
	if (sta->ethertype == ETH_P_PRE_AUTH)
	{
		if (send(rtapd->eth_sock, buf, len, 0) < 0)
			perror("send[WPA2 pre-auth]");
		DBGPRINT(RT_DEBUG_INFO,"ieee802_1x_send::WPA2, pre-auth, len=%d\n", len);
	}
	else
	{
        if (RT_ioctl(rtapd, RTPRIV_IOCTL_RADIUS_DATA, buf, len, sta->ApIdx, 0))
        DBGPRINT(RT_DEBUG_ERROR,"ioctl failed for ieee802_1x_send(len=%d)\n", len);
	}

	free(buf);
}

void ieee802_1x_set_sta_authorized(rtapd *rtapd, struct sta_info *sta, int authorized)
{
	switch(authorized)
	{
		case 0:
			DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_Set_Sta_Authorized FAILED \n");
//			  Ap_free_sta(rtapd, sta);
			break;

		case 1:
			DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_Set_Sta_Authorized SUCCESSED  \n"); 		   
			
			// This connection completed without transmitting EAPoL-Key
			// Notify driver to set-up pairwise key based on its shared key
			if( sta->eapol_sm->authSuccess && sta->eapol_key_sign_len == 0 && sta->eapol_key_crypt_len == 0 )
			{
				UCHAR	MacAddr[MAC_ADDR_LEN];
				
				memcpy(MacAddr, sta->addr, MAC_ADDR_LEN);
				if (RT_ioctl(rtapd, RTPRIV_IOCTL_STATIC_WEP_COPY, (u8*)&MacAddr, sizeof(MacAddr), sta->ApIdx, 0))
				{				   
                	DBGPRINT(RT_DEBUG_ERROR,"Failed to RTPRIV_IOCTL_STATIC_WEP_COPY\n");
                	return;
				}   
	    	}
			break;	  
	}
}

void ieee802_1x_request_identity(rtapd *rtapd, struct sta_info *sta, u8 id)
{
	char *buf;
	struct eap_hdr *eap;
	int tlen;
	u8 *pos;

	ieee802_1x_new_auth_session(rtapd, sta);

	tlen = sizeof(*eap) + 1 ;

	buf = (char *) malloc(tlen);
	if (buf == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, "Could not allocate memory for identity request\n");
		return;
	}

	memset(buf, 0, tlen);

	eap = (struct eap_hdr *) buf;
	eap->code = EAP_CODE_REQUEST;
	eap->identifier = id;
	eap->length = htons(tlen);
	pos = (u8 *) (eap + 1);
	*pos++ = EAP_TYPE_IDENTITY;

	DBGPRINT(RT_DEBUG_INFO, "IEEE802_1X_Request_Identity %d bytes: \n",tlen);
	ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, buf, tlen);
	free(buf);
}

void ieee802_1x_tx_canned_eap(rtapd *rtapd, struct sta_info *sta, u8 id, int success)
{
	struct eap_hdr eap;

	memset(&eap, 0, sizeof(eap));

	eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
	eap.identifier = id;
	eap.length = htons(sizeof(eap));
	DBGPRINT(RT_DEBUG_TRACE,"ieee802_1x_tx_canned_eap : Send to Sta with Identifier %d\n",id);

	ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, (u8 *) &eap, sizeof(eap));
}

void ieee802_1x_tx_req(rtapd *rtapd, struct sta_info *sta, u8 id)
{
	struct eap_hdr *eap;

	if (sta->last_eap_radius == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Error: TxReq called for station " MACSTR ", but there "
			   "is no EAP request from the authentication server\n", MAC2STR(sta->addr));
		return;
	}

	eap = (struct eap_hdr *) sta->last_eap_radius;
	if (eap->identifier != id)
	{
		DBGPRINT(RT_DEBUG_WARN,"IEEE 802.1X: TxReq(%d) - changing id from %d\n", id, eap->identifier);
		eap->identifier = id;
	}

	ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET,	sta->last_eap_radius, sta->last_eap_radius_len);
}

static void ieee802_1x_tx_key_one(rtapd *hapd, struct sta_info *sta,
				  int index, int broadcast,
				  u8 *key_data, size_t key_len)
{
	u8 *buf, *ekey;
	struct ieee802_1x_hdr *hdr;
	struct ieee802_1x_eapol_key *key;
	struct timeval now;
	size_t len, ekey_len;
	u32 ntp_hi, ntp_lo, sec, usec;

	len = sizeof(*key) + key_len;
	buf = malloc(sizeof(*hdr) + len);
	if (buf == NULL)
		return;

	memset(buf, 0, sizeof(*hdr) + len);
	hdr = (struct ieee802_1x_hdr *) buf;
	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
	key->type = EAPOL_KEY_TYPE_RC4;
	key->key_length = htons(key_len);

	/* Set the NTP timestamp as the replay counter */
	gettimeofday(&now, NULL);
	sec = now.tv_sec;
	usec = now.tv_usec;

#define JAN_1970 0x83aa7e80UL /* seconds from 1900 to 1970 */
	ntp_hi = htonl(sec + JAN_1970);
	/* approximation of 2^32/1000000 * usec */
	ntp_lo = htonl(4295 * usec - (usec >> 5) - (usec >> 9));

	memcpy(&key->replay_counter[0], &ntp_hi, sizeof(u32));
	memcpy(&key->replay_counter[4], &ntp_lo, sizeof(u32));
	if (hostapd_get_rand(key->key_iv, sizeof(key->key_iv)))
	{
		DBGPRINT(RT_DEBUG_ERROR, "Could not get random numbers\n");
		free(buf);
		return;
	}

	key->key_index = index | (broadcast ? 0 : BIT(7));
//	if (hapd->conf->eapol_key_index_workaround) {
		/* According to some information, WinXP Supplicant seems to
		 * interrept bit7 as an indication whether the key is to be
		 * activated, so make it possible to enable workaround that
		 * sets this bit for all keys. */
//		key->key_index |= BIT(7);
//	}
	DBGPRINT(RT_DEBUG_TRACE, "key_index= %d key_length= %d \n",index, key_len);

	/* Key is encrypted using "Key-IV + sta->eapol_key_crypt" as the
	 * RC4-key */
	memcpy((u8 *) (key + 1), key_data, key_len);
	ekey_len = sizeof(key->key_iv) + sta->eapol_key_crypt_len;
	ekey = malloc(ekey_len);
	if (ekey == NULL)
	{
		DBGPRINT(RT_DEBUG_TRACE,"Could not encrypt key\n");
		free(buf);
		return;
	}
	memcpy(ekey, key->key_iv, sizeof(key->key_iv));
	memcpy(ekey + sizeof(key->key_iv), sta->eapol_key_crypt, sta->eapol_key_crypt_len);
	rc4((u8 *) (key + 1), key_len, ekey, ekey_len);
	free(ekey);

	/* This header is needed here for HMAC-MD5, but it will be regenerated in ieee802_1x_send() */
	hdr->version = EAPOL_VERSION;
	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
	hdr->length = htons(len);
	hmac_md5(sta->eapol_key_sign, sta->eapol_key_sign_len, buf, sizeof(*hdr) + len, key->key_signature);

	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
	free(buf);
}

void ieee802_1x_tx_key(rtapd *rtapd, struct sta_info *sta, u8 id)
{
	NDIS_802_11_KEY 	WepKey, *pWepKey;
       char individual_wep_key[WEP8021X_KEY_LEN];
	
	if (!sta->eapol_key_sign || !sta->eapol_key_crypt)
		return;

	memset(&WepKey, 0, sizeof(NDIS_802_11_KEY));
	pWepKey = &WepKey;

	// prepare EAPoL-key for broadcast key and send to STA 
	ieee802_1x_tx_key_one(rtapd, sta, rtapd->conf->DefaultKeyID[sta->ApIdx], 1, (u8*)rtapd->conf->IEEE8021X_ikey[sta->ApIdx], rtapd->conf->individual_wep_key_len[sta->ApIdx]);
	
	// use IOCTL cmd to add WEP key
	WepKey.KeyIndex =  0x80000000 | (rtapd->conf->DefaultKeyID[sta->ApIdx]);
	WepKey.KeyLength = rtapd->conf->individual_wep_key_len[sta->ApIdx];
	memcpy(WepKey.KeyMaterial, rtapd->conf->IEEE8021X_ikey[sta->ApIdx], rtapd->conf->individual_wep_key_len[sta->ApIdx]);
	memcpy(WepKey.addr, sta->addr, 6);

	// WPA2(pre-auth)
	if (sta->ethertype== ETH_P_PRE_AUTH)
	{
		if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_PMKID_CACHE, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), 0, 0))
		{
			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
			return;
		}
	}
	else
	{
		if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_WPA_KEY, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), sta->ApIdx, 0))
		{
			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_WPA_KEY\n");
			return;
		}
	}
       
    // Generate random unicast key and send to STA
    hostapd_get_rand((u8*)individual_wep_key, rtapd->conf->individual_wep_key_len[sta->ApIdx]);
    ieee802_1x_tx_key_one(rtapd, sta, rtapd->conf->individual_wep_key_idx[sta->ApIdx], 0, (u8*)individual_wep_key, rtapd->conf->individual_wep_key_len[sta->ApIdx]);

	// use IOCTL cmd to add WEP key
	WepKey.KeyIndex =  rtapd->conf->individual_wep_key_idx[sta->ApIdx];
	WepKey.KeyLength = rtapd->conf->individual_wep_key_len[sta->ApIdx];
	memcpy(WepKey.KeyMaterial, individual_wep_key, rtapd->conf->individual_wep_key_len[sta->ApIdx]);
	memcpy(WepKey.addr, sta->addr, 6);

	// WPA2(pre-auth)
	if (sta->ethertype == ETH_P_PRE_AUTH)
	{
		if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_PMKID_CACHE, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), 0, 0))
		{
			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
			return;
		}
	}
	else
	{
		if (RT_ioctl(rtapd, RTPRIV_IOCTL_ADD_WPA_KEY, (u8*)&WepKey, sizeof(NDIS_802_11_KEY), sta->ApIdx, 0))
		{
			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_WPA_KEY\n");
			return;
		}
	}
}

static void ieee802_1x_encapsulate_radius(rtapd *rtapd, struct sta_info *sta, u8 *eap, size_t len)
{
	struct radius_msg *msg;
	char buf[128];

	sta->radius_identifier = Radius_client_get_id(rtapd);
	msg = Radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, sta->radius_identifier);
	if (msg == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR, "Could not create net RADIUS packet\n");
		return;
	}

	Radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(sta));

	if (sta->identity && !Radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, sta->identity, sta->identity_len))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add User-Name\n");
		goto fail;
	}
	   // apd->conf->own_ip_addr is filled according to configuration file
	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &rtapd->conf->own_ip_addr, 4))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-IP-Address\n");
		goto fail;
	}

	if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-Port\n");
		goto fail;
	}
	
	snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(rtapd->own_addr[sta->ApIdx]));
	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, buf, strlen(buf)))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add Called-Station-Id\n");
		goto fail;
	}

	snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(sta->addr));
	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, buf, strlen(buf)))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add Calling-Station-Id\n");
		goto fail;
	}

	/* TODO: should probably check MTU from driver config; 2304 is max for
	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
	 */
	if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add Framed-MTU\n");
		goto fail;
	}

	if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-Port-Type\n");
		goto fail;
	}

	snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, buf, strlen(buf)))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add Connect-Info\n");
		goto fail;
	}

	if (eap && !Radius_msg_add_eap(msg, eap, len))
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not add EAP-Message\n");
		goto fail;
	}

	/* State attribute must be copied if and only if this packet is
	 * Access-Request reply to the previous Access-Challenge */
	if (sta->last_recv_radius && sta->last_recv_radius->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE)
	{
		int res = Radius_msg_copy_attr(msg, sta->last_recv_radius, RADIUS_ATTR_STATE);
		if (res < 0)
		{
			DBGPRINT(RT_DEBUG_ERROR,"Could not copy State attribute from previous Access-Challenge\n");
			goto fail;
		}
	}

	Radius_client_send(rtapd, msg, RADIUS_AUTH);
	return;

fail:
	Radius_msg_free(msg);
	free(msg);
}

static void handle_eap_response(struct sta_info *sta, struct eap_hdr *eap, u8 *data, size_t len)
{
	u8 type;

	assert(sta->eapol_sm != NULL);

	if (eap->identifier != sta->eapol_sm->currentId)
	{
		DBGPRINT(RT_DEBUG_INFO,"EAP Identifier of the Response-Identity from " MACSTR
			   " does not match (was %d, expected %d)\n",
			   MAC2STR(sta->addr), eap->identifier,
			   sta->eapol_sm->currentId);
		// didn't check identifier..  reasonable ?
		return;
	}

	if (len < 1)
	{
		DBGPRINT(RT_DEBUG_WARN,"too short response data\n");
		return;
	}

	if (sta->last_eap_supp != NULL)
		free(sta->last_eap_supp);
	       sta->last_eap_supp_len = sizeof(*eap) + len;
	       sta->last_eap_supp = (u8 *) malloc(sta->last_eap_supp_len);
	if (sta->last_eap_supp == NULL)
	{
		DBGPRINT(RT_DEBUG_ERROR,"Could not alloc memory for last EAP Response\n");
		return;
	}

	memcpy(sta->last_eap_supp, eap, sizeof(*eap));
	memcpy(sta->last_eap_supp + sizeof(*eap), data, len);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -