📄 driver_ralink.c
字号:
/*
***************************************************************************
* Ralink Tech Inc.
* 5F, No. 36 Taiyuan St.
* Jhubei City
* Hsinchu County 302, Taiwan, R.O.C.
*
* (c) Copyright 2002-2008, Ralink Technology, Inc.
*
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
************************************************************************/
/*
* WPA Supplicant - driver interaction with Ralink rt73.o driver
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h> /* The L2 protocols */
#include <netinet/in.h>
//#include <linux/wireless.h>
#include "wireless_copy.h"
#include "common.h"
#include "driver.h"
#include "l2_packet.h"
#include "eloop.h"
#include "wpa_supplicant.h"
#include "priv_netlink.h"
#include "wpa.h"
#include "driver_ralink.h"
#include "wpa_supplicant_i.h"
#include "config_ssid.h"
#include "config.h"
static int scanning_done = 1;
struct wpa_driver_ralink_data {
void *ctx;
int ioctl_sock;
int event_sock;
char ifname[IFNAMSIZ + 1];
u8 *assoc_req_ies;
size_t assoc_req_ies_len;
u8 *assoc_resp_ies;
size_t assoc_resp_ies_len;
int no_of_pmkid;
struct ndis_pmkid_entry *pmkid;
int we_version_compiled;
};
static int ralink_set_oid(struct wpa_driver_ralink_data *drv, unsigned short oid,
char *data, int len)
{
char *buf;
struct iwreq iwr;
buf = os_malloc(len);
if (buf == NULL)
return -1;
memset(buf, 0,len);
memset(&iwr, 0, sizeof(iwr));
strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.flags = oid;
iwr.u.data.flags |= OID_GET_SET_TOGGLE;
if (data)
memcpy(buf, data, len);
iwr.u.data.pointer = (caddr_t) buf;
iwr.u.data.length = len;
if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0)
{
wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
__func__, oid, len);
os_free(buf);
return -1;
}
os_free(buf);
return 0;
}
static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
{
struct wpa_driver_ralink_data *drv = priv;
struct iwreq iwr;
int ret = 0;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
memset(&iwr, 0, sizeof(iwr));
strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0)
{
perror("ioctl[SIOCGIWAP]");
ret = -1;
}
memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
return ret;
}
static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
{
struct wpa_driver_ralink_data *drv = priv;
struct wpa_supplicant *wpa_s = drv->ctx;
struct wpa_ssid *entry;
int ssid_len;
u8 bssid[ETH_ALEN];
u8 ssid_str[MAX_SSID_LEN];
struct iwreq iwr;
int result = 0;
int ret = 0;
BOOLEAN ieee8021x_mode = FALSE;
BOOLEAN ieee8021x_required_key = FALSE;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
memset(&iwr, 0, sizeof(iwr));
strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.essid.pointer = (caddr_t) ssid;
iwr.u.essid.length = 32;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0)
{
perror("ioctl[SIOCGIWESSID]");
ret = -1;
} else
ret = iwr.u.essid.length;
if(ret <= 0)
return ret;
ssid_len = ret;
memset(ssid_str, 0, MAX_SSID_LEN);
memcpy(ssid_str, ssid, ssid_len);
if(wpa_s->conf->ap_scan == 0)
{
// Read BSSID form driver
if (wpa_driver_ralink_get_bssid(priv, bssid) < 0)
{
wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
return ret;
}
entry = wpa_s->conf->ssid;
while (entry)
{
if (!entry->disabled && ssid_len == entry->ssid_len && memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
(!entry->bssid_set || memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
{
// match the config of driver
result = 1;
break;
}
entry = entry->next;
}
if(result)
{
wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and ieee_required_keys parameters to driver");
// set 802.1x mode and ieee_required_keys parameter
if(entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA)
{
if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
ieee8021x_required_key = TRUE;
ieee8021x_mode = TRUE;
}
if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
{
wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
}
else
{
wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
}
if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
{
wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
}
else
{
wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
entry->eapol_flags);
}
}
}
return ret;
}
static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
const u8 *ssid, size_t ssid_len)
{
NDIS_802_11_SSID *buf;
int ret = 0;
struct iwreq iwr;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
buf = (NDIS_802_11_SSID *)os_malloc(sizeof(NDIS_802_11_SSID));
if (buf == NULL)
return -1;
memset(buf, 0, sizeof(buf));
buf->SsidLength = ssid_len;
memcpy(buf->Ssid, ssid, ssid_len);
memset(&iwr, 0, sizeof(iwr));
strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.flags = OID_802_11_SSID;
iwr.u.data.flags |= OID_GET_SET_TOGGLE;
iwr.u.data.pointer = (caddr_t) buf;
iwr.u.data.length = sizeof(NDIS_802_11_SSID);
if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0)
{
perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
ret = -1;
}
os_free(buf);
return ret;
}
static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
const u8 *data, size_t data_len)
{
NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
int i;
union wpa_event_data event;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
if (data_len < 8)
{
wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
"Event (len=%d)", data_len);
return;
}
pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d "
"NumCandidates %d",
(int) pmkid->Version, (int) pmkid->NumCandidates);
if (pmkid->Version != 1)
{
wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate List "
"Version %d", (int) pmkid->Version);
return;
}
if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE))
{
wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List underflow");
return;
}
memset(&event, 0, sizeof(event));
for (i = 0; i < pmkid->NumCandidates; i++)
{
PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
wpa_printf(MSG_DEBUG, "RALINK: %d: " MACSTR " Flags 0x%x",
i, MAC2STR(p->BSSID), (int) p->Flags);
memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
event.pmkid_candidate.index = i;
event.pmkid_candidate.preauth =
p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
&event);
}
}
static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
{
int len, count, i, ret;
struct ndis_pmkid_entry *entry;
NDIS_802_11_PMKID *p;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
count = 0;
entry = drv->pmkid;
while (entry)
{
count++;
if (count >= drv->no_of_pmkid)
break;
entry = entry->next;
}
len = 8 + count * sizeof(BSSID_INFO);
p = os_malloc(len);
if (p == NULL)
return -1;
memset(p, 0, len);
p->Length = len;
p->BSSIDInfoCount = count;
entry = drv->pmkid;
for (i = 0; i < count; i++)
{
memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
entry = entry->next;
}
wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (const u8 *) p, len);
ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
os_free(p);
return ret;
}
static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
const u8 *pmkid)
{
struct wpa_driver_ralink_data *drv = priv;
struct ndis_pmkid_entry *entry, *prev;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
if (drv->no_of_pmkid == 0)
return 0;
prev = NULL;
entry = drv->pmkid;
while (entry)
{
if (memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
break;
prev = entry;
entry = entry->next;
}
if (entry)
{
/* Replace existing entry for this BSSID and move it into the
* beginning of the list. */
memcpy(entry->pmkid, pmkid, 16);
if (prev)
{
prev->next = entry->next;
entry->next = drv->pmkid;
drv->pmkid = entry;
}
}
else
{
entry = os_malloc(sizeof(*entry));
if (entry)
{
memcpy(entry->bssid, bssid, ETH_ALEN);
memcpy(entry->pmkid, pmkid, 16);
entry->next = drv->pmkid;
drv->pmkid = entry;
}
}
return wpa_driver_ralink_set_pmkid(drv);
}
static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
const u8 *pmkid)
{
struct wpa_driver_ralink_data *drv = priv;
struct ndis_pmkid_entry *entry, *prev;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
if (drv->no_of_pmkid == 0)
return 0;
entry = drv->pmkid;
prev = NULL;
drv->pmkid = NULL;
while (entry)
{
if (memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
memcmp(entry->pmkid, pmkid, 16) == 0)
{
if (prev)
prev->next = entry->next;
else
drv->pmkid = entry->next;
os_free(entry);
break;
}
prev = entry;
entry = entry->next;
}
return wpa_driver_ralink_set_pmkid(drv);
}
static int wpa_driver_ralink_flush_pmkid(void *priv)
{
struct wpa_driver_ralink_data *drv = priv;
NDIS_802_11_PMKID p;
struct ndis_pmkid_entry *pmkid, *prev;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
if (drv->no_of_pmkid == 0)
return 0;
pmkid = drv->pmkid;
drv->pmkid = NULL;
while (pmkid)
{
prev = pmkid;
pmkid = pmkid->next;
os_free(prev);
}
memset(&p, 0, sizeof(p));
p.Length = 8;
p.BSSIDInfoCount = 0;
wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
(const u8 *) &p, 8);
return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
}
static void
wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
void *ctx, char *custom)
{
union wpa_event_data data;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
memset(&data, 0, sizeof(data));
/* Host AP driver */
if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0)
{
//receive a MICFAILURE report
data.michael_mic_failure.unicast =
strstr(custom, " unicast ") != NULL;
/* TODO: parse parameters(?) */
wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
}
else if (strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0)
{
//receive assoc. req. IEs
char *spos;
int bytes;
spos = custom + 17;
//get IE's length
//bytes = strlen(spos);
bytes = drv->assoc_req_ies_len + drv->assoc_resp_ies_len;
if (!bytes)
return;
data.assoc_info.req_ies = os_malloc(bytes);
if (data.assoc_info.req_ies == NULL)
return;
data.assoc_info.req_ies_len = bytes;
memcpy(data.assoc_info.req_ies, spos, bytes);
//skip the '\0' byte
spos += bytes + 1;
data.assoc_info.resp_ies = NULL;
data.assoc_info.resp_ies_len = 0;
if (strncmp(spos, " RespIEs=", 9) == 0)
{
//receive assoc. resp. IEs
spos += 9;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -