rtl8188eu: Add hostapd and configurationb file

Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net>
This commit is contained in:
Larry Finger 2013-11-27 14:23:24 -06:00
parent 7638be5ee7
commit e275d5ba1f
477 changed files with 220879 additions and 0 deletions

11
hostapd-0.8/src/Makefile Normal file
View file

@ -0,0 +1,11 @@
SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps
all:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
clean:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
rm -f *~
install:
for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done

View file

@ -0,0 +1,8 @@
all:
@echo Nothing to be made.
clean:
rm -f *~ *.o *.d
install:
@echo Nothing to be made.

View file

@ -0,0 +1,505 @@
/*
* hostapd / RADIUS Accounting
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "drivers/driver.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "ap_config.h"
#include "sta_info.h"
#include "ap_drv_ops.h"
#include "accounting.h"
/* Default interval in seconds for polling TX/RX octets from the driver if
* STA is not using interim accounting. This detects wrap arounds for
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
static void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta);
static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
struct sta_info *sta,
int status_type)
{
struct radius_msg *msg;
char buf[128];
u8 *val;
size_t len;
int i;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
if (msg == NULL) {
printf("Could not create net RADIUS packet\n");
return NULL;
}
if (sta) {
radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
os_snprintf(buf, sizeof(buf), "%08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Acct-Session-Id\n");
goto fail;
}
} else {
radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
status_type)) {
printf("Could not add Acct-Status-Type\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
hapd->conf->ieee802_1x ?
RADIUS_ACCT_AUTHENTIC_RADIUS :
RADIUS_ACCT_AUTHENTIC_LOCAL)) {
printf("Could not add Acct-Authentic\n");
goto fail;
}
if (sta) {
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
if (!val) {
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
MAC2STR(sta->addr));
val = (u8 *) buf;
len = os_strlen(buf);
}
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
len)) {
printf("Could not add User-Name\n");
goto fail;
}
}
if (hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
printf("Could not add NAS-IP-Address\n");
goto fail;
}
#ifdef CONFIG_IPV6
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
printf("Could not add NAS-IPv6-Address\n");
goto fail;
}
#endif /* CONFIG_IPV6 */
if (hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
printf("Could not add NAS-Identifier\n");
goto fail;
}
if (sta &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
printf("Could not add NAS-Port\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Called-Station-Id\n");
goto fail;
}
if (sta) {
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(sta->addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
goto fail;
}
if (!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
printf("Could not add NAS-Port-Type\n");
goto fail;
}
os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
radius_sta_rate(hapd, sta) / 2,
(radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
radius_mode_txt(hapd));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
}
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
i);
if (val == NULL)
break;
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
val, len)) {
printf("Could not add Class\n");
goto fail;
}
}
}
return msg;
fail:
radius_msg_free(msg);
return NULL;
}
static int accounting_sta_update_stats(struct hostapd_data *hapd,
struct sta_info *sta,
struct hostap_sta_driver_data *data)
{
if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
return -1;
if (sta->last_rx_bytes > data->rx_bytes)
sta->acct_input_gigawords++;
if (sta->last_tx_bytes > data->tx_bytes)
sta->acct_output_gigawords++;
sta->last_rx_bytes = data->rx_bytes;
sta->last_tx_bytes = data->tx_bytes;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
"Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
"Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
sta->last_rx_bytes, sta->acct_input_gigawords,
sta->last_tx_bytes, sta->acct_output_gigawords);
return 0;
}
static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
int interval;
if (sta->acct_interim_interval) {
accounting_sta_interim(hapd, sta);
interval = sta->acct_interim_interval;
} else {
struct hostap_sta_driver_data data;
accounting_sta_update_stats(hapd, sta, &data);
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
}
eloop_register_timeout(interval, 0, accounting_interim_update,
hapd, sta);
}
/**
* accounting_sta_start - Start STA accounting
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
int interval;
if (sta->acct_session_started)
return;
accounting_sta_get_id(hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"starting accounting session %08X-%08X",
sta->acct_session_id_hi, sta->acct_session_id_lo);
time(&sta->acct_session_start);
sta->last_rx_bytes = sta->last_tx_bytes = 0;
sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
hostapd_drv_sta_clear_stats(hapd, sta->addr);
if (!hapd->conf->radius->acct_server)
return;
if (sta->acct_interim_interval)
interval = sta->acct_interim_interval;
else
interval = ACCT_DEFAULT_UPDATE_INTERVAL;
eloop_register_timeout(interval, 0, accounting_interim_update,
hapd, sta);
msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
if (msg)
radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr);
sta->acct_session_started = 1;
}
static void accounting_sta_report(struct hostapd_data *hapd,
struct sta_info *sta, int stop)
{
struct radius_msg *msg;
int cause = sta->acct_terminate_cause;
struct hostap_sta_driver_data data;
struct os_time now;
u32 gigawords;
if (!hapd->conf->radius->acct_server)
return;
msg = accounting_msg(hapd, sta,
stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
if (!msg) {
printf("Could not create RADIUS Accounting message\n");
return;
}
os_get_time(&now);
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
now.sec - sta->acct_session_start)) {
printf("Could not add Acct-Session-Time\n");
goto fail;
}
if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_PACKETS,
data.rx_packets)) {
printf("Could not add Acct-Input-Packets\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
data.tx_packets)) {
printf("Could not add Acct-Output-Packets\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_INPUT_OCTETS,
data.rx_bytes)) {
printf("Could not add Acct-Input-Octets\n");
goto fail;
}
gigawords = sta->acct_input_gigawords;
#if __WORDSIZE == 64
gigawords += data.rx_bytes >> 32;
#endif
if (gigawords &&
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
gigawords)) {
printf("Could not add Acct-Input-Gigawords\n");
goto fail;
}
if (!radius_msg_add_attr_int32(msg,
RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
data.tx_bytes)) {
printf("Could not add Acct-Output-Octets\n");
goto fail;
}
gigawords = sta->acct_output_gigawords;
#if __WORDSIZE == 64
gigawords += data.tx_bytes >> 32;
#endif
if (gigawords &&
!radius_msg_add_attr_int32(
msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
gigawords)) {
printf("Could not add Acct-Output-Gigawords\n");
goto fail;
}
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
now.sec)) {
printf("Could not add Event-Timestamp\n");
goto fail;
}
if (eloop_terminated())
cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
if (stop && cause &&
!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
cause)) {
printf("Could not add Acct-Terminate-Cause\n");
goto fail;
}
radius_client_send(hapd->radius, msg,
stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
sta->addr);
return;
fail:
radius_msg_free(msg);
}
/**
* accounting_sta_interim - Send a interim STA accounting report
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->acct_session_started)
accounting_sta_report(hapd, sta, 0);
}
/**
* accounting_sta_stop - Stop STA accounting
* @hapd: hostapd BSS data
* @sta: The station
*/
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->acct_session_started) {
accounting_sta_report(hapd, sta, 1);
eloop_cancel_timeout(accounting_interim_update, hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"stopped accounting session %08X-%08X",
sta->acct_session_id_hi,
sta->acct_session_id_lo);
sta->acct_session_started = 0;
}
}
static void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta)
{
sta->acct_session_id_lo = hapd->acct_session_id_lo++;
if (hapd->acct_session_id_lo == 0) {
hapd->acct_session_id_hi++;
}
sta->acct_session_id_hi = hapd->acct_session_id_hi;
}
/**
* accounting_receive - Process the RADIUS frames from Accounting Server
* @msg: RADIUS response message
* @req: RADIUS request message
* @shared_secret: RADIUS shared secret
* @shared_secret_len: Length of shared_secret in octets
* @data: Context data (struct hostapd_data *)
* Returns: Processing status
*/
static RadiusRxResult
accounting_receive(struct radius_msg *msg, struct radius_msg *req,
const u8 *shared_secret, size_t shared_secret_len,
void *data)
{
if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
printf("Unknown RADIUS message code\n");
return RADIUS_RX_UNKNOWN;
}
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
printf("Incoming RADIUS packet did not have correct "
"Authenticator - dropped\n");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
return RADIUS_RX_PROCESSED;
}
static void accounting_report_state(struct hostapd_data *hapd, int on)
{
struct radius_msg *msg;
if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
return;
/* Inform RADIUS server that accounting will start/stop so that the
* server can close old accounting sessions. */
msg = accounting_msg(hapd, NULL,
on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
if (!msg)
return;
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
{
printf("Could not add Acct-Terminate-Cause\n");
radius_msg_free(msg);
return;
}
radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL);
}
/**
* accounting_init: Initialize accounting
* @hapd: hostapd BSS data
* Returns: 0 on success, -1 on failure
*/
int accounting_init(struct hostapd_data *hapd)
{
struct os_time now;
/* Acct-Session-Id should be unique over reboots. If reliable clock is
* not available, this could be replaced with reboot counter, etc. */
os_get_time(&now);
hapd->acct_session_id_hi = now.sec;
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))
return -1;
accounting_report_state(hapd, 1);
return 0;
}
/**
* accounting_deinit: Deinitilize accounting
* @hapd: hostapd BSS data
*/
void accounting_deinit(struct hostapd_data *hapd)
{
accounting_report_state(hapd, 0);
}

View file

@ -0,0 +1,45 @@
/*
* hostapd / RADIUS Accounting
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef ACCOUNTING_H
#define ACCOUNTING_H
void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_NO_ACCOUNTING
static inline void accounting_sta_start(struct hostapd_data *hapd,
struct sta_info *sta)
{
}
static inline void accounting_sta_stop(struct hostapd_data *hapd,
struct sta_info *sta)
{
}
static inline int accounting_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void accounting_deinit(struct hostapd_data *hapd)
{
}
#else /* CONFIG_NO_ACCOUNTING */
void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
int accounting_init(struct hostapd_data *hapd);
void accounting_deinit(struct hostapd_data *hapd);
#endif /* CONFIG_NO_ACCOUNTING */
#endif /* ACCOUNTING_H */

View file

@ -0,0 +1,627 @@
/*
* hostapd / Configuration helper functions
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "crypto/sha1.h"
#include "radius/radius_client.h"
#include "common/ieee802_11_defs.h"
#include "common/eapol_common.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
#include "sta_info.h"
#include "ap_config.h"
static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
{
struct hostapd_vlan *vlan, *prev;
vlan = bss->vlan;
prev = NULL;
while (vlan) {
prev = vlan;
vlan = vlan->next;
os_free(prev);
}
bss->vlan = NULL;
}
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
{
bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
bss->logger_syslog = (unsigned int) -1;
bss->logger_stdout = (unsigned int) -1;
bss->auth_algs = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
bss->wep_rekeying_period = 300;
/* use key0 in individual key and key1 in broadcast key */
bss->broadcast_key_idx_min = 1;
bss->broadcast_key_idx_max = 2;
bss->eap_reauth_period = 3600;
bss->wpa_group_rekey = 600;
bss->wpa_gmk_rekey = 86400;
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
bss->wpa_pairwise = WPA_CIPHER_TKIP;
bss->wpa_group = WPA_CIPHER_TKIP;
bss->rsn_pairwise = 0;
bss->max_num_sta = MAX_STA_COUNT;
bss->dtim_period = 2;
bss->radius_server_auth_port = 1812;
bss->ap_max_inactivity = AP_MAX_INACTIVITY;
bss->eapol_version = EAPOL_VERSION;
bss->max_listen_interval = 65535;
bss->pwd_group = 19; /* ECC: GF(p=256) */
#ifdef CONFIG_IEEE80211W
bss->assoc_sa_query_max_timeout = 1000;
bss->assoc_sa_query_retry_timeout = 201;
#endif /* CONFIG_IEEE80211W */
#ifdef EAP_SERVER_FAST
/* both anonymous and authenticated provisioning */
bss->eap_fast_prov = 3;
bss->pac_key_lifetime = 7 * 24 * 60 * 60;
bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
#endif /* EAP_SERVER_FAST */
/* Set to -1 as defaults depends on HT in setup */
bss->wmm_enabled = -1;
#ifdef CONFIG_IEEE80211R
bss->ft_over_ds = 1;
#endif /* CONFIG_IEEE80211R */
}
struct hostapd_config * hostapd_config_defaults(void)
{
#define ecw2cw(ecw) ((1 << (ecw)) - 1)
struct hostapd_config *conf;
struct hostapd_bss_config *bss;
const int aCWmin = 4, aCWmax = 10;
const struct hostapd_wmm_ac_params ac_bk =
{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
{ aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
const struct hostapd_tx_queue_params txq_bk =
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
const struct hostapd_tx_queue_params txq_be =
{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
const struct hostapd_tx_queue_params txq_vi =
{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
const struct hostapd_tx_queue_params txq_vo =
{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
(ecw2cw(aCWmin) + 1) / 2 - 1, 15};
#undef ecw2cw
conf = os_zalloc(sizeof(*conf));
bss = os_zalloc(sizeof(*bss));
if (conf == NULL || bss == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"configuration data.");
os_free(conf);
os_free(bss);
return NULL;
}
bss->radius = os_zalloc(sizeof(*bss->radius));
if (bss->radius == NULL) {
os_free(conf);
os_free(bss);
return NULL;
}
hostapd_config_defaults_bss(bss);
conf->num_bss = 1;
conf->bss = bss;
conf->beacon_int = 100;
conf->rts_threshold = -1; /* use driver default: 2347 */
conf->fragm_threshold = -1; /* user driver default: 2346 */
conf->send_probe_response = 1;
conf->wmm_ac_params[0] = ac_be;
conf->wmm_ac_params[1] = ac_bk;
conf->wmm_ac_params[2] = ac_vi;
conf->wmm_ac_params[3] = ac_vo;
conf->tx_queue[0] = txq_vo;
conf->tx_queue[1] = txq_vi;
conf->tx_queue[2] = txq_be;
conf->tx_queue[3] = txq_bk;
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
return conf;
}
int hostapd_mac_comp(const void *a, const void *b)
{
return os_memcmp(a, b, sizeof(macaddr));
}
int hostapd_mac_comp_empty(const void *a)
{
macaddr empty = { 0 };
return os_memcmp(a, empty, sizeof(macaddr));
}
static int hostapd_config_read_wpa_psk(const char *fname,
struct hostapd_ssid *ssid)
{
FILE *f;
char buf[128], *pos;
int line = 0, ret = 0, len, ok;
u8 addr[ETH_ALEN];
struct hostapd_wpa_psk *psk;
if (!fname)
return 0;
f = fopen(fname, "r");
if (!f) {
wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
return -1;
}
while (fgets(buf, sizeof(buf), f)) {
line++;
if (buf[0] == '#')
continue;
pos = buf;
while (*pos != '\0') {
if (*pos == '\n') {
*pos = '\0';
break;
}
pos++;
}
if (buf[0] == '\0')
continue;
if (hwaddr_aton(buf, addr)) {
wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
"line %d in '%s'", buf, line, fname);
ret = -1;
break;
}
psk = os_zalloc(sizeof(*psk));
if (psk == NULL) {
wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
ret = -1;
break;
}
if (is_zero_ether_addr(addr))
psk->group = 1;
else
os_memcpy(psk->addr, addr, ETH_ALEN);
pos = buf + 17;
if (*pos == '\0') {
wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
line, fname);
os_free(psk);
ret = -1;
break;
}
pos++;
ok = 0;
len = os_strlen(pos);
if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
else if (len >= 8 && len < 64) {
pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
4096, psk->psk, PMK_LEN);
ok = 1;
}
if (!ok) {
wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
"'%s'", pos, line, fname);
os_free(psk);
ret = -1;
break;
}
psk->next = ssid->wpa_psk;
ssid->wpa_psk = psk;
}
fclose(f);
return ret;
}
static int hostapd_derive_psk(struct hostapd_ssid *ssid)
{
ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (ssid->wpa_psk == NULL) {
wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
return -1;
}
wpa_hexdump_ascii(MSG_DEBUG, "SSID",
(u8 *) ssid->ssid, ssid->ssid_len);
wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
(u8 *) ssid->wpa_passphrase,
os_strlen(ssid->wpa_passphrase));
pbkdf2_sha1(ssid->wpa_passphrase,
ssid->ssid, ssid->ssid_len,
4096, ssid->wpa_psk->psk, PMK_LEN);
wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
ssid->wpa_psk->psk, PMK_LEN);
return 0;
}
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
struct hostapd_ssid *ssid = &conf->ssid;
if (ssid->wpa_passphrase != NULL) {
if (ssid->wpa_psk != NULL) {
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
"instead of passphrase");
} else {
wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
"passphrase");
if (hostapd_derive_psk(ssid) < 0)
return -1;
}
ssid->wpa_psk->group = 1;
}
if (ssid->wpa_psk_file) {
if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
&conf->ssid))
return -1;
}
return 0;
}
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
{
int i;
if (a->idx != b->idx || a->default_len != b->default_len)
return 1;
for (i = 0; i < NUM_WEP_KEYS; i++)
if (a->len[i] != b->len[i] ||
os_memcmp(a->key[i], b->key[i], a->len[i]) != 0)
return 1;
return 0;
}
static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
int num_servers)
{
int i;
for (i = 0; i < num_servers; i++) {
os_free(servers[i].shared_secret);
}
os_free(servers);
}
static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
{
os_free(user->identity);
os_free(user->password);
os_free(user);
}
static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
{
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
os_free(keys->key[i]);
keys->key[i] = NULL;
}
}
static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
struct hostapd_wpa_psk *psk, *prev;
struct hostapd_eap_user *user, *prev_user;
if (conf == NULL)
return;
psk = conf->ssid.wpa_psk;
while (psk) {
prev = psk;
psk = psk->next;
os_free(prev);
}
os_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
hostapd_config_free_wep(&conf->ssid.wep);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
user = conf->eap_user;
while (user) {
prev_user = user;
user = user->next;
hostapd_config_free_eap_user(prev_user);
}
os_free(conf->dump_log_name);
os_free(conf->eap_req_id_text);
os_free(conf->accept_mac);
os_free(conf->deny_mac);
os_free(conf->nas_identifier);
hostapd_config_free_radius(conf->radius->auth_servers,
conf->radius->num_auth_servers);
hostapd_config_free_radius(conf->radius->acct_servers,
conf->radius->num_acct_servers);
os_free(conf->rsn_preauth_interfaces);
os_free(conf->ctrl_interface);
os_free(conf->ca_cert);
os_free(conf->server_cert);
os_free(conf->private_key);
os_free(conf->private_key_passwd);
os_free(conf->dh_file);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
os_free(conf->radius_server_clients);
os_free(conf->test_socket);
os_free(conf->radius);
hostapd_config_free_vlan(conf);
if (conf->ssid.dyn_vlan_keys) {
struct hostapd_ssid *ssid = &conf->ssid;
size_t i;
for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
if (ssid->dyn_vlan_keys[i] == NULL)
continue;
hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
os_free(ssid->dyn_vlan_keys[i]);
}
os_free(ssid->dyn_vlan_keys);
ssid->dyn_vlan_keys = NULL;
}
#ifdef CONFIG_IEEE80211R
{
struct ft_remote_r0kh *r0kh, *r0kh_prev;
struct ft_remote_r1kh *r1kh, *r1kh_prev;
r0kh = conf->r0kh_list;
conf->r0kh_list = NULL;
while (r0kh) {
r0kh_prev = r0kh;
r0kh = r0kh->next;
os_free(r0kh_prev);
}
r1kh = conf->r1kh_list;
conf->r1kh_list = NULL;
while (r1kh) {
r1kh_prev = r1kh;
r1kh = r1kh->next;
os_free(r1kh_prev);
}
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_WPS
os_free(conf->wps_pin_requests);
os_free(conf->device_name);
os_free(conf->manufacturer);
os_free(conf->model_name);
os_free(conf->model_number);
os_free(conf->serial_number);
os_free(conf->config_methods);
os_free(conf->ap_pin);
os_free(conf->extra_cred);
os_free(conf->ap_settings);
os_free(conf->upnp_iface);
os_free(conf->friendly_name);
os_free(conf->manufacturer_url);
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
#endif /* CONFIG_WPS */
}
/**
* hostapd_config_free - Free hostapd configuration
* @conf: Configuration data from hostapd_config_read().
*/
void hostapd_config_free(struct hostapd_config *conf)
{
size_t i;
if (conf == NULL)
return;
for (i = 0; i < conf->num_bss; i++)
hostapd_config_free_bss(&conf->bss[i]);
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf);
}
/**
* hostapd_maclist_found - Find a MAC address from a list
* @list: MAC address list
* @num_entries: Number of addresses in the list
* @addr: Address to search for
* @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
* Returns: 1 if address is in the list or 0 if not.
*
* Perform a binary search for given MAC address from a pre-sorted list.
*/
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
const u8 *addr, int *vlan_id)
{
int start, end, middle, res;
start = 0;
end = num_entries - 1;
while (start <= end) {
middle = (start + end) / 2;
res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
if (res == 0) {
if (vlan_id)
*vlan_id = list[middle].vlan_id;
return 1;
}
if (res < 0)
start = middle + 1;
else
end = middle - 1;
}
return 0;
}
int hostapd_rate_found(int *list, int rate)
{
int i;
if (list == NULL)
return 0;
for (i = 0; list[i] >= 0; i++)
if (list[i] == rate)
return 1;
return 0;
}
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
{
struct hostapd_vlan *v = vlan;
while (v) {
if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
return v->ifname;
v = v->next;
}
return NULL;
}
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *prev_psk)
{
struct hostapd_wpa_psk *psk;
int next_ok = prev_psk == NULL;
for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
if (next_ok &&
(psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
return psk->psk;
if (psk->psk == prev_psk)
next_ok = 1;
}
return NULL;
}
const struct hostapd_eap_user *
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2)
{
struct hostapd_eap_user *user = conf->eap_user;
#ifdef CONFIG_WPS
if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
static struct hostapd_eap_user wsc_enrollee;
os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
wsc_enrollee.methods[0].method = eap_server_get_type(
"WSC", &wsc_enrollee.methods[0].vendor);
return &wsc_enrollee;
}
if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
static struct hostapd_eap_user wsc_registrar;
os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
wsc_registrar.methods[0].method = eap_server_get_type(
"WSC", &wsc_registrar.methods[0].vendor);
wsc_registrar.password = (u8 *) conf->ap_pin;
wsc_registrar.password_len = conf->ap_pin ?
os_strlen(conf->ap_pin) : 0;
return &wsc_registrar;
}
#endif /* CONFIG_WPS */
while (user) {
if (!phase2 && user->identity == NULL) {
/* Wildcard match */
break;
}
if (user->phase2 == !!phase2 && user->wildcard_prefix &&
identity_len >= user->identity_len &&
os_memcmp(user->identity, identity, user->identity_len) ==
0) {
/* Wildcard prefix match */
break;
}
if (user->phase2 == !!phase2 &&
user->identity_len == identity_len &&
os_memcmp(user->identity, identity, identity_len) == 0)
break;
user = user->next;
}
return user;
}

View file

@ -0,0 +1,417 @@
/*
* hostapd / Configuration definitions and helpers functions
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef HOSTAPD_CONFIG_H
#define HOSTAPD_CONFIG_H
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
#include "wps/wps.h"
#define MAX_STA_COUNT 2007
#define MAX_VLAN_ID 4094
typedef u8 macaddr[ETH_ALEN];
struct mac_acl_entry {
macaddr addr;
int vlan_id;
};
struct hostapd_radius_servers;
struct ft_remote_r0kh;
struct ft_remote_r1kh;
#define HOSTAPD_MAX_SSID_LEN 32
#define NUM_WEP_KEYS 4
struct hostapd_wep_keys {
u8 idx;
u8 *key[NUM_WEP_KEYS];
size_t len[NUM_WEP_KEYS];
int keys_set;
size_t default_len; /* key length used for dynamic key generation */
};
typedef enum hostap_security_policy {
SECURITY_PLAINTEXT = 0,
SECURITY_STATIC_WEP = 1,
SECURITY_IEEE_802_1X = 2,
SECURITY_WPA_PSK = 3,
SECURITY_WPA = 4
} secpolicy;
struct hostapd_ssid {
char ssid[HOSTAPD_MAX_SSID_LEN + 1];
size_t ssid_len;
int ssid_set;
char vlan[IFNAMSIZ + 1];
secpolicy security_policy;
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
char *wpa_psk_file;
struct hostapd_wep_keys wep;
#define DYNAMIC_VLAN_DISABLED 0
#define DYNAMIC_VLAN_OPTIONAL 1
#define DYNAMIC_VLAN_REQUIRED 2
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct hostapd_wep_keys **dyn_vlan_keys;
size_t max_dyn_vlan_keys;
};
#define VLAN_ID_WILDCARD -1
struct hostapd_vlan {
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
char ifname[IFNAMSIZ + 1];
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
#define DVLAN_CLEAN_BR 0x1
#define DVLAN_CLEAN_VLAN 0x2
#define DVLAN_CLEAN_VLAN_PORT 0x4
#define DVLAN_CLEAN_WLAN_PORT 0x8
int clean;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
};
#define PMK_LEN 32
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
int group;
u8 psk[PMK_LEN];
u8 addr[ETH_ALEN];
};
#define EAP_USER_MAX_METHODS 8
struct hostapd_eap_user {
struct hostapd_eap_user *next;
u8 *identity;
size_t identity_len;
struct {
int vendor;
u32 method;
} methods[EAP_USER_MAX_METHODS];
u8 *password;
size_t password_len;
int phase2;
int force_version;
unsigned int wildcard_prefix:1;
unsigned int password_hash:1; /* whether password is hashed with
* nt_password_hash() */
int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
};
#define NUM_TX_QUEUES 4
struct hostapd_tx_queue_params {
int aifs;
int cwmin;
int cwmax;
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
};
struct hostapd_wmm_ac_params {
int cwmin;
int cwmax;
int aifs;
int txop_limit; /* in units of 32us */
int admission_control_mandatory;
};
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
char wds_bridge[IFNAMSIZ + 1];
enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
unsigned int logger_syslog; /* module bitfield */
unsigned int logger_stdout; /* module bitfield */
char *dump_log_name; /* file name for state dump (SIGUSR1) */
int max_num_sta; /* maximum number of STAs in station table */
int dtim_period;
int ieee802_1x; /* use IEEE 802.1X */
int eapol_version;
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
char *eap_sim_db;
struct hostapd_ip_addr own_ip_addr;
char *nas_identifier;
struct hostapd_radius_servers *radius;
int acct_interim_interval;
struct hostapd_ssid ssid;
char *eap_req_id_text; /* optional displayable message sent with
* EAP Request-Identity */
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
* frames */
enum {
ACCEPT_UNLESS_DENIED = 0,
DENY_UNLESS_ACCEPTED = 1,
USE_EXTERNAL_RADIUS_AUTH = 2
} macaddr_acl;
struct mac_acl_entry *accept_mac;
int num_accept_mac;
struct mac_acl_entry *deny_mac;
int num_deny_mac;
int wds_sta;
int isolate;
int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
int wpa_key_mgmt;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
unsigned int assoc_sa_query_max_timeout;
/* dot11AssociationSAQueryRetryTimeout (in TUs) */
int assoc_sa_query_retry_timeout;
#endif /* CONFIG_IEEE80211W */
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
int rsn_pairwise;
int rsn_preauth;
char *rsn_preauth_interfaces;
int peerkey;
#ifdef CONFIG_IEEE80211R
/* IEEE 802.11r - Fast BSS Transition */
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r1_key_holder[FT_R1KH_ID_LEN];
u32 r0_key_lifetime;
u32 reassociation_deadline;
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
#endif /* CONFIG_IEEE80211R */
char *ctrl_interface; /* directory for UNIX domain sockets */
#ifndef CONFIG_NATIVE_WINDOWS
gid_t ctrl_interface_gid;
#endif /* CONFIG_NATIVE_WINDOWS */
int ctrl_interface_gid_set;
char *ca_cert;
char *server_cert;
char *private_key;
char *private_key_passwd;
int check_crl;
char *dh_file;
u8 *pac_opaque_encr_key;
u8 *eap_fast_a_id;
size_t eap_fast_a_id_len;
char *eap_fast_a_id_info;
int eap_fast_prov;
int pac_key_lifetime;
int pac_key_refresh_time;
int eap_sim_aka_result_ind;
int tnc;
int fragment_size;
u16 pwd_group;
char *radius_server_clients;
int radius_server_auth_port;
int radius_server_ipv6;
char *test_socket; /* UNIX domain socket path for driver_test */
int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
* address instead of individual address
* (for driver_wired.c).
*/
int ap_max_inactivity;
int ignore_broadcast_ssid;
int wmm_enabled;
int wmm_uapsd;
struct hostapd_vlan *vlan, *vlan_tail;
macaddr bssid;
/*
* Maximum listen interval that STAs can use when associating with this
* BSS. If a STA tries to use larger value, the association will be
* denied with status code 51.
*/
u16 max_listen_interval;
int okc; /* Opportunistic Key Caching */
int wps_state;
#ifdef CONFIG_WPS
int ap_setup_locked;
u8 uuid[16];
char *wps_pin_requests;
char *device_name;
char *manufacturer;
char *model_name;
char *model_number;
char *serial_number;
u8 device_type[WPS_DEV_TYPE_LEN];
char *config_methods;
u8 os_version[4];
char *ap_pin;
int skip_cred_build;
u8 *extra_cred;
size_t extra_cred_len;
int wps_cred_processing;
u8 *ap_settings;
size_t ap_settings_len;
char *upnp_iface;
char *friendly_name;
char *manufacturer_url;
char *model_description;
char *model_url;
char *upc;
struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
#endif /* CONFIG_WPS */
#define P2P_ENABLED BIT(0)
#define P2P_GROUP_OWNER BIT(1)
#define P2P_GROUP_FORMATION BIT(2)
#define P2P_MANAGE BIT(3)
#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
int p2p;
int disassoc_low_ack;
#define TDLS_PROHIBIT BIT(0)
#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
int tdls;
int disable_11n;
};
/**
* struct hostapd_config - Per-radio interface configuration
*/
struct hostapd_config {
struct hostapd_bss_config *bss, *last_bss;
size_t num_bss;
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
u8 send_probe_response;
u8 channel;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
SHORT_PREAMBLE = 1
} preamble;
enum {
CTS_PROTECTION_AUTOMATIC = 0,
CTS_PROTECTION_FORCE_ENABLED = 1,
CTS_PROTECTION_FORCE_DISABLED = 2,
CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
} cts_protection_type;
int *supported_rates;
int *basic_rates;
const struct wpa_driver_ops *driver;
int ap_table_max_size;
int ap_table_expiration_time;
char country[3]; /* first two octets: country code as described in
* ISO/IEC 3166-1. Third octet:
* ' ' (ascii 32): all environments
* 'O': Outdoor environemnt only
* 'I': Indoor environment only
*/
int ieee80211d;
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
/*
* WMM AC parameters, in same order as 802.1D, i.e.
* 0 = BE (best effort)
* 1 = BK (background)
* 2 = VI (video)
* 3 = VO (voice)
*/
struct hostapd_wmm_ac_params wmm_ac_params[4];
int ht_op_mode_fixed;
u16 ht_capab;
int ieee80211n;
int secondary_channel;
int require_ht;
};
int hostapd_mac_comp(const void *a, const void *b);
int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
const u8 *addr, int *vlan_id);
int hostapd_rate_found(int *list, int rate);
int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
struct hostapd_wep_keys *b);
const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
const u8 *addr, const u8 *prev_psk);
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
int vlan_id);
const struct hostapd_eap_user *
hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2);
#endif /* HOSTAPD_CONFIG_H */

View file

@ -0,0 +1,632 @@
/*
* hostapd - Driver operations
* Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
u32 hostapd_sta_flags_to_drv(u32 flags)
{
int res = 0;
if (flags & WLAN_STA_AUTHORIZED)
res |= WPA_STA_AUTHORIZED;
if (flags & WLAN_STA_WMM)
res |= WPA_STA_WMM;
if (flags & WLAN_STA_SHORT_PREAMBLE)
res |= WPA_STA_SHORT_PREAMBLE;
if (flags & WLAN_STA_MFP)
res |= WPA_STA_MFP;
return res;
}
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
{
struct wpabuf *beacon, *proberesp, *assocresp = NULL;
int ret;
if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
return 0;
beacon = hapd->wps_beacon_ie;
proberesp = hapd->wps_probe_resp_ie;
#ifdef CONFIG_P2P
if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL)
beacon = NULL;
else {
beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
wpabuf_len(hapd->wps_beacon_ie) : 0) +
(hapd->p2p_beacon_ie ?
wpabuf_len(hapd->p2p_beacon_ie) : 0));
if (beacon == NULL)
return -1;
if (hapd->wps_beacon_ie)
wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
if (hapd->p2p_beacon_ie)
wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
}
if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL)
proberesp = NULL;
else {
proberesp = wpabuf_alloc(
(hapd->wps_probe_resp_ie ?
wpabuf_len(hapd->wps_probe_resp_ie) : 0) +
(hapd->p2p_probe_resp_ie ?
wpabuf_len(hapd->p2p_probe_resp_ie) : 0));
if (proberesp == NULL) {
wpabuf_free(beacon);
return -1;
}
if (hapd->wps_probe_resp_ie)
wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
if (hapd->p2p_probe_resp_ie)
wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
struct wpabuf *a;
a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0));
if (a) {
u8 *start, *p;
if (beacon)
wpabuf_put_buf(a, beacon);
if (beacon != hapd->wps_beacon_ie)
wpabuf_free(beacon);
start = wpabuf_put(a, 0);
p = hostapd_eid_p2p_manage(hapd, start);
wpabuf_put(a, p - start);
beacon = a;
}
a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) :
0));
if (a) {
u8 *start, *p;
if (proberesp)
wpabuf_put_buf(a, proberesp);
if (proberesp != hapd->wps_probe_resp_ie)
wpabuf_free(proberesp);
start = wpabuf_put(a, 0);
p = hostapd_eid_p2p_manage(hapd, start);
wpabuf_put(a, p - start);
proberesp = a;
}
}
#endif /* CONFIG_P2P_MANAGER */
#ifdef CONFIG_WPS2
if (hapd->conf->wps_state)
assocresp = wps_build_assoc_resp_ie();
#endif /* CONFIG_WPS2 */
#ifdef CONFIG_P2P_MANAGER
if (hapd->conf->p2p & P2P_MANAGE) {
struct wpabuf *a;
a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) :
0));
if (a) {
u8 *start, *p;
start = wpabuf_put(a, 0);
p = hostapd_eid_p2p_manage(hapd, start);
wpabuf_put(a, p - start);
if (assocresp) {
wpabuf_put_buf(a, assocresp);
wpabuf_free(assocresp);
}
assocresp = a;
}
}
#endif /* CONFIG_P2P_MANAGER */
ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
assocresp);
if (beacon != hapd->wps_beacon_ie)
wpabuf_free(beacon);
if (proberesp != hapd->wps_probe_resp_ie)
wpabuf_free(proberesp);
wpabuf_free(assocresp);
return ret;
}
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized)
{
if (authorized) {
return hostapd_sta_set_flags(hapd, sta->addr,
hostapd_sta_flags_to_drv(
sta->flags),
WPA_STA_AUTHORIZED, ~0);
}
return hostapd_sta_set_flags(hapd, sta->addr,
hostapd_sta_flags_to_drv(sta->flags),
0, ~WPA_STA_AUTHORIZED);
}
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_flags, total_flags, flags_and, flags_or;
total_flags = hostapd_sta_flags_to_drv(sta->flags);
set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
sta->auth_alg == WLAN_AUTH_FT) &&
sta->flags & WLAN_STA_AUTHORIZED)
set_flags |= WPA_STA_AUTHORIZED;
flags_or = total_flags & set_flags;
flags_and = total_flags | ~set_flags;
return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
flags_or, flags_and);
}
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled)
{
struct wpa_bss_params params;
os_memset(&params, 0, sizeof(params));
params.ifname = ifname;
params.enabled = enabled;
if (enabled) {
params.wpa = hapd->conf->wpa;
params.ieee802_1x = hapd->conf->ieee802_1x;
params.wpa_group = hapd->conf->wpa_group;
params.wpa_pairwise = hapd->conf->wpa_pairwise;
params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
params.rsn_preauth = hapd->conf->rsn_preauth;
#ifdef CONFIG_IEEE80211W
params.ieee80211w = hapd->conf->ieee80211w;
#endif /* CONFIG_IEEE80211W */
}
return hostapd_set_ieee8021x(hapd, &params);
}
static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL)
return 0;
return hapd->driver->set_intra_bss(hapd->drv_priv, !value);
}
int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection)
{
int ret = 0;
int preamble;
#ifdef CONFIG_IEEE80211N
u8 buf[60], *ht_capab, *ht_oper, *pos;
pos = buf;
ht_capab = pos;
pos = hostapd_eid_ht_capabilities(hapd, pos);
ht_oper = pos;
pos = hostapd_eid_ht_operation(hapd, pos);
if (pos > ht_oper && ht_oper > ht_capab &&
hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
ht_oper + 2, ht_oper[1])) {
wpa_printf(MSG_ERROR, "Could not set HT capabilities "
"for kernel driver");
ret = -1;
}
#endif /* CONFIG_IEEE80211N */
if (hostapd_set_cts_protect(hapd, use_protection)) {
wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
"driver");
ret = -1;
}
if (hapd->iface->current_mode &&
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
hostapd_set_short_slot_time(hapd,
hapd->iface->num_sta_no_short_slot_time
> 0 ? 0 : 1)) {
wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
"in kernel driver");
ret = -1;
}
if (hapd->iface->num_sta_no_short_preamble == 0 &&
hapd->iconf->preamble == SHORT_PREAMBLE)
preamble = SHORT_PREAMBLE;
else
preamble = LONG_PREAMBLE;
if (hostapd_set_preamble(hapd, preamble)) {
wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
"driver");
ret = -1;
}
if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) &&
hapd->conf->isolate) {
wpa_printf(MSG_ERROR, "Could not enable AP isolation in "
"kernel driver");
ret = -1;
}
return ret;
}
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
{
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
NULL, NULL, force_ifname, if_addr, NULL);
}
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
{
return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
}
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
int val)
{
const char *bridge = NULL;
if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
return 0;
if (hapd->conf->wds_bridge[0])
bridge = hapd->conf->wds_bridge;
else if (hapd->conf->bridge[0])
bridge = hapd->conf->bridge;
return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
bridge);
}
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab)
{
struct hostapd_sta_add_params params;
if (hapd->driver == NULL)
return 0;
if (hapd->driver->sta_add == NULL)
return 0;
os_memset(&params, 0, sizeof(params));
params.addr = addr;
params.aid = aid;
params.capability = capability;
params.supp_rates = supp_rates;
params.supp_rates_len = supp_rates_len;
params.listen_interval = listen_interval;
params.ht_capabilities = ht_capab;
return hapd->driver->sta_add(hapd->drv_priv, &params);
}
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
return 0;
return hapd->driver->set_privacy(hapd->drv_priv, enabled);
}
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len)
{
if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
return 0;
return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len);
}
int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
{
if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL)
return 0;
return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len);
}
int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
{
if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL)
return 0;
return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len);
}
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
const char *bridge)
{
if (hapd->driver == NULL || hapd->driver->if_add == NULL)
return -1;
return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
bss_ctx, drv_priv, force_ifname, if_addr,
bridge);
}
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname)
{
if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
return -1;
return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
}
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
struct wpa_bss_params *params)
{
if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
return 0;
return hapd->driver->set_ieee8021x(hapd->drv_priv, params);
}
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq)
{
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
return 0;
return hapd->driver->get_seqnum(ifname, hapd->drv_priv, addr, idx,
seq);
}
int hostapd_flush(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->flush == NULL)
return 0;
return hapd->driver->flush(hapd->drv_priv);
}
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
int channel, int ht_enabled, int sec_channel_offset)
{
struct hostapd_freq_params data;
if (hapd->driver == NULL)
return 0;
if (hapd->driver->set_freq == NULL)
return 0;
os_memset(&data, 0, sizeof(data));
data.mode = mode;
data.freq = freq;
data.channel = channel;
data.ht_enabled = ht_enabled;
data.sec_channel_offset = sec_channel_offset;
return hapd->driver->set_freq(hapd->drv_priv, &data);
}
int hostapd_set_rts(struct hostapd_data *hapd, int rts)
{
if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
return 0;
return hapd->driver->set_rts(hapd->drv_priv, rts);
}
int hostapd_set_frag(struct hostapd_data *hapd, int frag)
{
if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
return 0;
return hapd->driver->set_frag(hapd->drv_priv, frag);
}
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and)
{
if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
return 0;
return hapd->driver->sta_set_flags(hapd->drv_priv, addr, total_flags,
flags_or, flags_and);
}
int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
int *basic_rates, int mode)
{
if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
return 0;
return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
basic_rates, mode);
}
int hostapd_set_country(struct hostapd_data *hapd, const char *country)
{
if (hapd->driver == NULL ||
hapd->driver->set_country == NULL)
return 0;
return hapd->driver->set_country(hapd->drv_priv, country);
}
int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
return 0;
return hapd->driver->set_cts_protect(hapd->drv_priv, value);
}
int hostapd_set_preamble(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
return 0;
return hapd->driver->set_preamble(hapd->drv_priv, value);
}
int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
{
if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
return 0;
return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
}
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
return 0;
return hapd->driver->set_tx_queue_params(hapd->drv_priv, queue, aifs,
cw_min, cw_max, burst_time);
}
int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
const u8 *mask)
{
if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
return 1;
return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
}
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags)
{
if (hapd->driver == NULL ||
hapd->driver->get_hw_feature_data == NULL)
return NULL;
return hapd->driver->get_hw_feature_data(hapd->drv_priv, num_modes,
flags);
}
int hostapd_driver_commit(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->commit == NULL)
return 0;
return hapd->driver->commit(hapd->drv_priv);
}
int hostapd_set_ht_params(struct hostapd_data *hapd,
const u8 *ht_capab, size_t ht_capab_len,
const u8 *ht_oper, size_t ht_oper_len)
{
if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
ht_capab == NULL || ht_oper == NULL)
return 0;
return hapd->driver->set_ht_params(hapd->drv_priv,
ht_capab, ht_capab_len,
ht_oper, ht_oper_len);
}
int hostapd_drv_none(struct hostapd_data *hapd)
{
return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
}
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params)
{
if (hapd->driver && hapd->driver->scan2)
return hapd->driver->scan2(hapd->drv_priv, params);
return -1;
}
struct wpa_scan_results * hostapd_driver_get_scan_results(
struct hostapd_data *hapd)
{
if (hapd->driver && hapd->driver->get_scan_results2)
return hapd->driver->get_scan_results2(hapd->drv_priv);
return NULL;
}
int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration)
{
if (hapd->driver && hapd->driver->set_noa)
return hapd->driver->set_noa(hapd->drv_priv, count, start,
duration);
return -1;
}
int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len)
{
if (hapd->driver == NULL || hapd->driver->set_key == NULL)
return 0;
return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
key_idx, set_tx, seq, seq_len, key,
key_len);
}
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len)
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
}
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
return 0;
return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
reason);
}
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
return 0;
return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
reason);
}

View file

@ -0,0 +1,197 @@
/*
* hostapd - Driver operations
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AP_DRV_OPS
#define AP_DRV_OPS
enum wpa_driver_if_type;
struct wpa_bss_params;
struct wpa_driver_scan_params;
struct ieee80211_ht_capabilities;
u32 hostapd_sta_flags_to_drv(u32 flags);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
int enabled);
int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection);
int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
int val);
int hostapd_sta_add(struct hostapd_data *hapd,
const u8 *addr, u16 aid, u16 capability,
const u8 *supp_rates, size_t supp_rates_len,
u16 listen_interval,
const struct ieee80211_ht_capabilities *ht_capab);
int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
size_t elem_len);
int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname, const u8 *addr, void *bss_ctx,
void **drv_priv, char *force_ifname, u8 *if_addr,
const char *bridge);
int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
const char *ifname);
int hostapd_set_ieee8021x(struct hostapd_data *hapd,
struct wpa_bss_params *params);
int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
int channel, int ht_enabled, int sec_channel_offset);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
int hostapd_set_frag(struct hostapd_data *hapd, int frag);
int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
int total_flags, int flags_or, int flags_and);
int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
int *basic_rates, int mode);
int hostapd_set_country(struct hostapd_data *hapd, const char *country);
int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
int hostapd_set_preamble(struct hostapd_data *hapd, int value);
int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
int cw_min, int cw_max, int burst_time);
int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
const u8 *mask);
struct hostapd_hw_modes *
hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
u16 *flags);
int hostapd_driver_commit(struct hostapd_data *hapd);
int hostapd_set_ht_params(struct hostapd_data *hapd,
const u8 *ht_capab, size_t ht_capab_len,
const u8 *ht_oper, size_t ht_oper_len);
int hostapd_drv_none(struct hostapd_data *hapd);
int hostapd_driver_scan(struct hostapd_data *hapd,
struct wpa_driver_scan_params *params);
struct wpa_scan_results * hostapd_driver_get_scan_results(
struct hostapd_data *hapd);
int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration);
int hostapd_drv_set_key(const char *ifname,
struct hostapd_data *hapd,
enum wpa_alg alg, const u8 *addr,
int key_idx, int set_tx,
const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len);
int hostapd_drv_send_mlme(struct hostapd_data *hapd,
const void *msg, size_t len);
int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
const u8 *addr, int reason);
int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
const u8 *addr, int reason);
#include "drivers/driver.h"
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
if (hapd->driver == NULL ||
hapd->driver->hapd_set_countermeasures == NULL)
return 0;
return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
}
static inline int hostapd_drv_set_sta_vlan(const char *ifname,
struct hostapd_data *hapd,
const u8 *addr, int vlan_id)
{
if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
return 0;
return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
vlan_id);
}
static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
return 0;
return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
}
static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
return 0;
return hapd->driver->sta_remove(hapd->drv_priv, addr);
}
static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
const u8 *addr, const u8 *data,
size_t data_len, int encrypt,
u32 flags)
{
if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
return 0;
return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
data_len, encrypt,
hapd->own_addr, flags);
}
static inline int hostapd_drv_read_sta_data(
struct hostapd_data *hapd, struct hostap_sta_driver_data *data,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
return -1;
return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
}
static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
return 0;
return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
}
static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd,
const u8 *head, size_t head_len,
const u8 *tail, size_t tail_len,
int dtim_period, int beacon_int)
{
if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
return 0;
return hapd->driver->set_beacon(hapd->drv_priv,
head, head_len, tail, tail_len,
dtim_period, beacon_int);
}
static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
const u8 *mac, int accepted,
u32 session_timeout)
{
if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
return 0;
return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
session_timeout);
}
static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
const u8 *mac)
{
if (hapd->driver == NULL ||
hapd->driver->set_radius_acl_expire == NULL)
return 0;
return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
}
#endif /* AP_DRV_OPS */

View file

@ -0,0 +1,399 @@
/*
* hostapd / AP table
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "beacon.h"
#include "ap_list.h"
/* AP list is a double linked list with head->prev pointing to the end of the
* list and tail->next = NULL. Entries are moved to the head of the list
* whenever a beacon has been received from the AP in question. The tail entry
* in this link will thus be the least recently used entry. */
static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
{
int i;
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
iface->conf->channel != ap->channel)
return 0;
if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
return 1;
for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
int rate = (ap->supported_rates[i] & 0x7f) * 5;
if (rate == 60 || rate == 90 || rate > 110)
return 0;
}
return 1;
}
struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
{
struct ap_info *s;
s = iface->ap_hash[STA_HASH(ap)];
while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
s = s->hnext;
return s;
}
static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
{
if (iface->ap_list) {
ap->prev = iface->ap_list->prev;
iface->ap_list->prev = ap;
} else
ap->prev = ap;
ap->next = iface->ap_list;
iface->ap_list = ap;
}
static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
{
if (iface->ap_list == ap)
iface->ap_list = ap->next;
else
ap->prev->next = ap->next;
if (ap->next)
ap->next->prev = ap->prev;
else if (iface->ap_list)
iface->ap_list->prev = ap->prev;
}
static void ap_ap_iter_list_add(struct hostapd_iface *iface,
struct ap_info *ap)
{
if (iface->ap_iter_list) {
ap->iter_prev = iface->ap_iter_list->iter_prev;
iface->ap_iter_list->iter_prev = ap;
} else
ap->iter_prev = ap;
ap->iter_next = iface->ap_iter_list;
iface->ap_iter_list = ap;
}
static void ap_ap_iter_list_del(struct hostapd_iface *iface,
struct ap_info *ap)
{
if (iface->ap_iter_list == ap)
iface->ap_iter_list = ap->iter_next;
else
ap->iter_prev->iter_next = ap->iter_next;
if (ap->iter_next)
ap->iter_next->iter_prev = ap->iter_prev;
else if (iface->ap_iter_list)
iface->ap_iter_list->iter_prev = ap->iter_prev;
}
static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
{
ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
iface->ap_hash[STA_HASH(ap->addr)] = ap;
}
static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
{
struct ap_info *s;
s = iface->ap_hash[STA_HASH(ap->addr)];
if (s == NULL) return;
if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
return;
}
while (s->hnext != NULL &&
os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
s = s->hnext;
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
printf("AP: could not remove AP " MACSTR " from hash table\n",
MAC2STR(ap->addr));
}
static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
{
ap_ap_hash_del(iface, ap);
ap_ap_list_del(iface, ap);
ap_ap_iter_list_del(iface, ap);
iface->num_ap--;
os_free(ap);
}
static void hostapd_free_aps(struct hostapd_iface *iface)
{
struct ap_info *ap, *prev;
ap = iface->ap_list;
while (ap) {
prev = ap;
ap = ap->next;
ap_free_ap(iface, prev);
}
iface->ap_list = NULL;
}
int ap_ap_for_each(struct hostapd_iface *iface,
int (*func)(struct ap_info *s, void *data), void *data)
{
struct ap_info *s;
int ret = 0;
s = iface->ap_list;
while (s) {
ret = func(s, data);
if (ret)
break;
s = s->next;
}
return ret;
}
static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
{
struct ap_info *ap;
ap = os_zalloc(sizeof(struct ap_info));
if (ap == NULL)
return NULL;
/* initialize AP info data */
os_memcpy(ap->addr, addr, ETH_ALEN);
ap_ap_list_add(iface, ap);
iface->num_ap++;
ap_ap_hash_add(iface, ap);
ap_ap_iter_list_add(iface, ap);
if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
MACSTR " from AP table", MAC2STR(ap->prev->addr));
ap_free_ap(iface, ap->prev);
}
return ap;
}
void ap_list_process_beacon(struct hostapd_iface *iface,
const struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
struct hostapd_frame_info *fi)
{
struct ap_info *ap;
struct os_time now;
int new_ap = 0;
size_t len;
int set_beacon = 0;
if (iface->conf->ap_table_max_size < 1)
return;
ap = ap_get_ap(iface, mgmt->bssid);
if (!ap) {
ap = ap_ap_add(iface, mgmt->bssid);
if (!ap) {
printf("Failed to allocate AP information entry\n");
return;
}
new_ap = 1;
}
ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
if (elems->ssid) {
len = elems->ssid_len;
if (len >= sizeof(ap->ssid))
len = sizeof(ap->ssid) - 1;
os_memcpy(ap->ssid, elems->ssid, len);
ap->ssid[len] = '\0';
ap->ssid_len = len;
}
os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
len = 0;
if (elems->supp_rates) {
len = elems->supp_rates_len;
if (len > WLAN_SUPP_RATES_MAX)
len = WLAN_SUPP_RATES_MAX;
os_memcpy(ap->supported_rates, elems->supp_rates, len);
}
if (elems->ext_supp_rates) {
int len2;
if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
len2 = WLAN_SUPP_RATES_MAX - len;
else
len2 = elems->ext_supp_rates_len;
os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
len2);
}
ap->wpa = elems->wpa_ie != NULL;
if (elems->erp_info && elems->erp_info_len == 1)
ap->erp = elems->erp_info[0];
else
ap->erp = -1;
if (elems->ds_params && elems->ds_params_len == 1)
ap->channel = elems->ds_params[0];
else if (fi)
ap->channel = fi->channel;
if (elems->ht_capabilities)
ap->ht_support = 1;
else
ap->ht_support = 0;
ap->num_beacons++;
os_get_time(&now);
ap->last_beacon = now.sec;
if (fi) {
ap->ssi_signal = fi->ssi_signal;
ap->datarate = fi->datarate;
}
if (!new_ap && ap != iface->ap_list) {
/* move AP entry into the beginning of the list so that the
* oldest entry is always in the end of the list */
ap_ap_list_del(iface, ap);
ap_ap_list_add(iface, ap);
}
if (!iface->olbc &&
ap_list_beacon_olbc(iface, ap)) {
iface->olbc = 1;
wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
"protection", MAC2STR(ap->addr));
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!iface->olbc_ht && !ap->ht_support) {
iface->olbc_ht = 1;
hostapd_ht_operation_update(iface);
wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
" - enable protection", MAC2STR(ap->addr));
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_set_beacons(iface);
}
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_iface *iface = eloop_ctx;
struct os_time now;
struct ap_info *ap;
int set_beacon = 0;
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
if (!iface->ap_list)
return;
os_get_time(&now);
while (iface->ap_list) {
ap = iface->ap_list->prev;
if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
now.sec)
break;
ap_free_ap(iface, ap);
}
if (iface->olbc || iface->olbc_ht) {
int olbc = 0;
int olbc_ht = 0;
ap = iface->ap_list;
while (ap && (olbc == 0 || olbc_ht == 0)) {
if (ap_list_beacon_olbc(iface, ap))
olbc = 1;
if (!ap->ht_support)
olbc_ht = 1;
ap = ap->next;
}
if (!olbc && iface->olbc) {
wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
iface->olbc = 0;
set_beacon++;
}
#ifdef CONFIG_IEEE80211N
if (!olbc_ht && iface->olbc_ht) {
wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
iface->olbc_ht = 0;
hostapd_ht_operation_update(iface);
set_beacon++;
}
#endif /* CONFIG_IEEE80211N */
}
if (set_beacon)
ieee802_11_set_beacons(iface);
}
int ap_list_init(struct hostapd_iface *iface)
{
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
return 0;
}
void ap_list_deinit(struct hostapd_iface *iface)
{
eloop_cancel_timeout(ap_list_timer, iface, NULL);
hostapd_free_aps(iface);
}

View file

@ -0,0 +1,78 @@
/*
* hostapd / AP table
* Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AP_LIST_H
#define AP_LIST_H
struct ap_info {
/* Note: next/prev pointers are updated whenever a new beacon is
* received because these are used to find the least recently used
* entries. iter_next/iter_prev are updated only when adding new BSSes
* and when removing old ones. These should be used when iterating
* through the table in a manner that allows beacons to be received
* during the iteration. */
struct ap_info *next; /* next entry in AP list */
struct ap_info *prev; /* previous entry in AP list */
struct ap_info *hnext; /* next entry in hash table list */
struct ap_info *iter_next; /* next entry in AP iteration list */
struct ap_info *iter_prev; /* previous entry in AP iteration list */
u8 addr[6];
u16 beacon_int;
u16 capability;
u8 supported_rates[WLAN_SUPP_RATES_MAX];
u8 ssid[33];
size_t ssid_len;
int wpa;
int erp; /* ERP Info or -1 if ERP info element not present */
int channel;
int datarate; /* in 100 kbps */
int ssi_signal;
int ht_support;
unsigned int num_beacons; /* number of beacon frames received */
os_time_t last_beacon;
int already_seen; /* whether API call AP-NEW has already fetched
* information about this AP */
};
struct ieee802_11_elems;
struct hostapd_frame_info;
struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
int ap_ap_for_each(struct hostapd_iface *iface,
int (*func)(struct ap_info *s, void *data), void *data);
void ap_list_process_beacon(struct hostapd_iface *iface,
const struct ieee80211_mgmt *mgmt,
struct ieee802_11_elems *elems,
struct hostapd_frame_info *fi);
#ifdef NEED_AP_MLME
int ap_list_init(struct hostapd_iface *iface);
void ap_list_deinit(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline int ap_list_init(struct hostapd_iface *iface)
{
return 0;
}
static inline void ap_list_deinit(struct hostapd_iface *iface)
{
}
#endif /* NEED_AP_MLME */
#endif /* AP_LIST_H */

View file

@ -0,0 +1,184 @@
/*
* hostapd / IEEE 802.11 MLME
* Copyright 2003-2006, Jouni Malinen <j@w1.fi>
* Copyright 2003-2004, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
#include "sta_info.h"
#include "ap_mlme.h"
#ifndef CONFIG_NO_HOSTAPD_LOGGER
static const char * mlme_auth_alg_str(int alg)
{
switch (alg) {
case WLAN_AUTH_OPEN:
return "OPEN_SYSTEM";
case WLAN_AUTH_SHARED_KEY:
return "SHARED_KEY";
case WLAN_AUTH_FT:
return "FT";
}
return "unknown";
}
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
/**
* mlme_authenticate_indication - Report the establishment of an authentication
* relationship with a specific peer MAC entity
* @hapd: BSS data
* @sta: peer STA data
*
* MLME calls this function as a result of the establishment of an
* authentication relationship with a specific peer MAC entity that
* resulted from an authentication procedure that was initiated by
* that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
* AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
*/
void mlme_authenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_deauthenticate_indication - Report the invalidation of an
* authentication relationship with a specific peer MAC entity
* @hapd: BSS data
* @sta: Peer STA data
* @reason_code: ReasonCode from Deauthentication frame
*
* MLME calls this function as a result of the invalidation of an
* authentication relationship with a specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*/
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_associate_indication - Report the establishment of an association with
* a specific peer MAC entity
* @hapd: BSS data
* @sta: peer STA data
*
* MLME calls this function as a result of the establishment of an
* association with a specific peer MAC entity that resulted from an
* association procedure that was initiated by that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*/
void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-ASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
if (sta->auth_alg != WLAN_AUTH_FT)
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_reassociate_indication - Report the establishment of an reassociation
* with a specific peer MAC entity
* @hapd: BSS data
* @sta: peer STA data
*
* MLME calls this function as a result of the establishment of an
* reassociation with a specific peer MAC entity that resulted from a
* reassociation procedure that was initiated by that specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*
* sta->previous_ap contains the "Current AP" information from ReassocReq.
*/
void mlme_reassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-REASSOCIATE.indication(" MACSTR ")",
MAC2STR(sta->addr));
if (sta->auth_alg != WLAN_AUTH_FT)
mlme_deletekeys_request(hapd, sta);
}
/**
* mlme_disassociate_indication - Report disassociation with a specific peer
* MAC entity
* @hapd: BSS data
* @sta: Peer STA data
* @reason_code: ReasonCode from Disassociation frame
*
* MLME calls this function as a result of the invalidation of an association
* relationship with a specific peer MAC entity.
*
* PeerSTAAddress = sta->addr
*/
void mlme_disassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
MAC2STR(sta->addr), reason_code);
mlme_deletekeys_request(hapd, sta);
}
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
const u8 *addr)
{
hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-MichaelMICFailure.indication(" MACSTR ")",
MAC2STR(addr));
}
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
HOSTAPD_LEVEL_DEBUG,
"MLME-DELETEKEYS.request(" MACSTR ")",
MAC2STR(sta->addr));
if (sta->wpa_sm)
wpa_remove_ptk(sta->wpa_sm);
}

View file

@ -0,0 +1,40 @@
/*
* hostapd / IEEE 802.11 MLME
* Copyright 2003, Jouni Malinen <j@w1.fi>
* Copyright 2003-2004, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef MLME_H
#define MLME_H
void mlme_authenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta);
void mlme_deauthenticate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code);
void mlme_associate_indication(struct hostapd_data *hapd,
struct sta_info *sta);
void mlme_reassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta);
void mlme_disassociate_indication(struct hostapd_data *hapd,
struct sta_info *sta, u16 reason_code);
void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
const u8 *addr);
void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* MLME_H */

View file

@ -0,0 +1,217 @@
/*
* Authentication server setup
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "crypto/tls.h"
#include "eap_server/eap.h"
#include "eap_server/eap_sim_db.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "radius/radius_server.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "authsrv.h"
#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA)
#define EAP_SIM_DB
#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */
#ifdef EAP_SIM_DB
static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx)
{
if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0)
return 1;
return 0;
}
static void hostapd_sim_db_cb(void *ctx, void *session_ctx)
{
struct hostapd_data *hapd = ctx;
if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) {
#ifdef RADIUS_SERVER
radius_server_eap_pending_cb(hapd->radius_srv, session_ctx);
#endif /* RADIUS_SERVER */
}
}
#endif /* EAP_SIM_DB */
#ifdef RADIUS_SERVER
static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
size_t identity_len, int phase2,
struct eap_user *user)
{
const struct hostapd_eap_user *eap_user;
int i, count;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
if (user == NULL)
return 0;
os_memset(user, 0, sizeof(*user));
count = EAP_USER_MAX_METHODS;
if (count > EAP_MAX_METHODS)
count = EAP_MAX_METHODS;
for (i = 0; i < count; i++) {
user->methods[i].vendor = eap_user->methods[i].vendor;
user->methods[i].method = eap_user->methods[i].method;
}
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
return -1;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
user->password_hash = eap_user->password_hash;
}
user->force_version = eap_user->force_version;
user->ttls_auth = eap_user->ttls_auth;
return 0;
}
static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
{
struct radius_server_conf srv;
struct hostapd_bss_config *conf = hapd->conf;
os_memset(&srv, 0, sizeof(srv));
srv.client_file = conf->radius_server_clients;
srv.auth_port = conf->radius_server_auth_port;
srv.conf_ctx = conf;
srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
srv.ssl_ctx = hapd->ssl_ctx;
srv.msg_ctx = hapd->msg_ctx;
srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
srv.eap_fast_a_id = conf->eap_fast_a_id;
srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
srv.eap_fast_prov = conf->eap_fast_prov;
srv.pac_key_lifetime = conf->pac_key_lifetime;
srv.pac_key_refresh_time = conf->pac_key_refresh_time;
srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
srv.tnc = conf->tnc;
srv.wps = hapd->wps;
srv.ipv6 = conf->radius_server_ipv6;
srv.get_eap_user = hostapd_radius_get_eap_user;
srv.eap_req_id_text = conf->eap_req_id_text;
srv.eap_req_id_text_len = conf->eap_req_id_text_len;
srv.pwd_group = conf->pwd_group;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
wpa_printf(MSG_ERROR, "RADIUS server initialization failed.");
return -1;
}
return 0;
}
#endif /* RADIUS_SERVER */
int authsrv_init(struct hostapd_data *hapd)
{
#ifdef EAP_TLS_FUNCS
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
hapd->conf->dh_file)) {
struct tls_connection_params params;
hapd->ssl_ctx = tls_init(NULL);
if (hapd->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
authsrv_deinit(hapd);
return -1;
}
os_memset(&params, 0, sizeof(params));
params.ca_cert = hapd->conf->ca_cert;
params.client_cert = hapd->conf->server_cert;
params.private_key = hapd->conf->private_key;
params.private_key_passwd = hapd->conf->private_key_passwd;
params.dh_file = hapd->conf->dh_file;
if (tls_global_set_params(hapd->ssl_ctx, &params)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
authsrv_deinit(hapd);
return -1;
}
if (tls_global_set_verify(hapd->ssl_ctx,
hapd->conf->check_crl)) {
wpa_printf(MSG_ERROR, "Failed to enable check_crl");
authsrv_deinit(hapd);
return -1;
}
}
#endif /* EAP_TLS_FUNCS */
#ifdef EAP_SIM_DB
if (hapd->conf->eap_sim_db) {
hapd->eap_sim_db_priv =
eap_sim_db_init(hapd->conf->eap_sim_db,
hostapd_sim_db_cb, hapd);
if (hapd->eap_sim_db_priv == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
"database interface");
authsrv_deinit(hapd);
return -1;
}
}
#endif /* EAP_SIM_DB */
#ifdef RADIUS_SERVER
if (hapd->conf->radius_server_clients &&
hostapd_setup_radius_srv(hapd))
return -1;
#endif /* RADIUS_SERVER */
return 0;
}
void authsrv_deinit(struct hostapd_data *hapd)
{
#ifdef RADIUS_SERVER
radius_server_deinit(hapd->radius_srv);
hapd->radius_srv = NULL;
#endif /* RADIUS_SERVER */
#ifdef EAP_TLS_FUNCS
if (hapd->ssl_ctx) {
tls_deinit(hapd->ssl_ctx);
hapd->ssl_ctx = NULL;
}
#endif /* EAP_TLS_FUNCS */
#ifdef EAP_SIM_DB
if (hapd->eap_sim_db_priv) {
eap_sim_db_deinit(hapd->eap_sim_db_priv);
hapd->eap_sim_db_priv = NULL;
}
#endif /* EAP_SIM_DB */
}

View file

@ -0,0 +1,21 @@
/*
* Authentication server setup
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AUTHSRV_H
#define AUTHSRV_H
int authsrv_init(struct hostapd_data *hapd);
void authsrv_deinit(struct hostapd_data *hapd);
#endif /* AUTHSRV_H */

540
hostapd-0.8/src/ap/beacon.c Normal file
View file

@ -0,0 +1,540 @@
/*
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#ifndef CONFIG_NATIVE_WINDOWS
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
#include "wmm.h"
#include "ap_config.h"
#include "sta_info.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "beacon.h"
static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
{
u8 erp = 0;
if (hapd->iface->current_mode == NULL ||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return 0;
switch (hapd->iconf->cts_protection_type) {
case CTS_PROTECTION_FORCE_ENABLED:
erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
break;
case CTS_PROTECTION_FORCE_DISABLED:
erp = 0;
break;
case CTS_PROTECTION_AUTOMATIC:
if (hapd->iface->olbc)
erp |= ERP_INFO_USE_PROTECTION;
/* continue */
case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
if (hapd->iface->num_sta_non_erp > 0) {
erp |= ERP_INFO_NON_ERP_PRESENT |
ERP_INFO_USE_PROTECTION;
}
break;
}
if (hapd->iface->num_sta_no_short_preamble > 0 ||
hapd->iconf->preamble == LONG_PREAMBLE)
erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
return erp;
}
static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
{
*eid++ = WLAN_EID_DS_PARAMS;
*eid++ = 1;
*eid++ = hapd->iconf->channel;
return eid;
}
static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
{
if (hapd->iface->current_mode == NULL ||
hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
return eid;
/* Set NonERP_present and use_protection bits if there
* are any associated NonERP stations. */
/* TODO: use_protection bit can be set to zero even if
* there are NonERP stations present. This optimization
* might be useful if NonERP stations are "quiet".
* See 802.11g/D6 E-1 for recommended practice.
* In addition, Non ERP present might be set, if AP detects Non ERP
* operation on other APs. */
/* Add ERP Information element */
*eid++ = WLAN_EID_ERP_INFO;
*eid++ = 1;
*eid++ = ieee802_11_erp_info(hapd);
return eid;
}
static u8 * hostapd_eid_country_add(u8 *pos, u8 *end, int chan_spacing,
struct hostapd_channel_data *start,
struct hostapd_channel_data *prev)
{
if (end - pos < 3)
return pos;
/* first channel number */
*pos++ = start->chan;
/* number of channels */
*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
/* maximum transmit power level */
*pos++ = start->max_tx_power;
return pos;
}
static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
int max_len)
{
u8 *pos = eid;
u8 *end = eid + max_len;
int i;
struct hostapd_hw_modes *mode;
struct hostapd_channel_data *start, *prev;
int chan_spacing = 1;
if (!hapd->iconf->ieee80211d || max_len < 6 ||
hapd->iface->current_mode == NULL)
return eid;
*pos++ = WLAN_EID_COUNTRY;
pos++; /* length will be set later */
os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
pos += 3;
mode = hapd->iface->current_mode;
if (mode->mode == HOSTAPD_MODE_IEEE80211A)
chan_spacing = 4;
start = prev = NULL;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (start && prev &&
prev->chan + chan_spacing == chan->chan &&
start->max_tx_power == chan->max_tx_power) {
prev = chan;
continue; /* can use same entry */
}
if (start) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
start = NULL;
}
/* Start new group */
start = prev = chan;
}
if (start) {
pos = hostapd_eid_country_add(pos, end, chan_spacing,
start, prev);
}
if ((pos - eid) & 1) {
if (end - pos < 1)
return eid;
*pos++ = 0; /* pad for 16-bit alignment */
}
eid[1] = (pos - eid) - 2;
return pos;
}
static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
struct sta_info *sta)
{
const u8 *ie;
size_t ielen;
ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
if (ie == NULL || ielen > len)
return eid;
os_memcpy(eid, ie, ielen);
return eid + ielen;
}
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
struct ieee80211_mgmt *resp;
struct ieee802_11_elems elems;
char *ssid;
u8 *pos, *epos;
const u8 *ie;
size_t ssid_len, ie_len;
struct sta_info *sta = NULL;
size_t buflen;
size_t i;
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
return;
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
mgmt->sa, ie, ie_len) > 0)
return;
if (!hapd->iconf->send_probe_response)
return;
if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
MAC2STR(mgmt->sa));
return;
}
ssid = NULL;
ssid_len = 0;
if ((!elems.ssid || !elems.supp_rates)) {
wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
"without SSID or supported rates element",
MAC2STR(mgmt->sa));
return;
}
#ifdef CONFIG_P2P
if (hapd->p2p && elems.wps_ie) {
struct wpabuf *wps;
wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
"due to mismatch with Requested Device "
"Type");
wpabuf_free(wps);
return;
}
wpabuf_free(wps);
}
#endif /* CONFIG_P2P */
if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
"broadcast SSID ignored", MAC2STR(mgmt->sa));
return;
}
sta = ap_get_sta(hapd, mgmt->sa);
#ifdef CONFIG_P2P
if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
P2P_WILDCARD_SSID_LEN) == 0) {
/* Process P2P Wildcard SSID like Wildcard SSID */
elems.ssid_len = 0;
}
#endif /* CONFIG_P2P */
if (elems.ssid_len == 0 ||
(elems.ssid_len == hapd->conf->ssid.ssid_len &&
os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
0)) {
ssid = hapd->conf->ssid.ssid;
ssid_len = hapd->conf->ssid.ssid_len;
if (sta)
sta->ssid_probe = &hapd->conf->ssid;
}
if (!ssid) {
if (!(mgmt->da[0] & 0x01)) {
char ssid_txt[33];
ieee802_11_print_ssid(ssid_txt, elems.ssid,
elems.ssid_len);
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")",
MAC2STR(mgmt->sa), ssid_txt,
MAC2STR(mgmt->da));
}
return;
}
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
#define MAX_PROBERESP_LEN 768
buflen = MAX_PROBERESP_LEN;
#ifdef CONFIG_WPS
if (hapd->wps_probe_resp_ie)
buflen += wpabuf_len(hapd->wps_probe_resp_ie);
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
if (hapd->p2p_probe_resp_ie)
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
#endif /* CONFIG_P2P */
resp = os_zalloc(buflen);
if (resp == NULL)
return;
epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_PROBE_RESP);
os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.probe_resp.beacon_int =
host_to_le16(hapd->iconf->beacon_int);
/* hardware or low-level driver will setup seq_ctrl and timestamp */
resp->u.probe_resp.capab_info =
host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
pos = resp->u.probe_resp.variable;
*pos++ = WLAN_EID_SSID;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
pos += ssid_len;
/* Supported rates */
pos = hostapd_eid_supp_rates(hapd, pos);
/* DS Params */
pos = hostapd_eid_ds_params(hapd, pos);
pos = hostapd_eid_country(hapd, pos, epos - pos);
/* ERP Information element */
pos = hostapd_eid_erp_info(hapd, pos);
/* Extended supported rates */
pos = hostapd_eid_ext_supp_rates(hapd, pos);
/* RSN, MDIE, WPA */
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
#ifdef CONFIG_IEEE80211N
pos = hostapd_eid_ht_capabilities(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
#endif /* CONFIG_IEEE80211N */
pos = hostapd_eid_ext_capab(hapd, pos);
/* Wi-Fi Alliance WMM */
pos = hostapd_eid_wmm(hapd, pos);
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
wpabuf_len(hapd->wps_probe_resp_ie));
pos += wpabuf_len(hapd->wps_probe_resp_ie);
}
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p &&
hapd->p2p_probe_resp_ie) {
os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
wpabuf_len(hapd->p2p_probe_resp_ie));
pos += wpabuf_len(hapd->p2p_probe_resp_ie);
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
P2P_MANAGE)
pos = hostapd_eid_p2p_manage(hapd, pos);
#endif /* CONFIG_P2P_MANAGER */
if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0)
perror("handle_probe_req: send");
os_free(resp);
wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
"SSID", MAC2STR(mgmt->sa),
elems.ssid_len == 0 ? "broadcast" : "our");
}
void ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct ieee80211_mgmt *head;
u8 *pos, *tail, *tailpos;
u16 capab_info;
size_t head_len, tail_len;
#ifdef CONFIG_P2P
if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED)
goto no_beacon;
#endif /* CONFIG_P2P */
#define BEACON_HEAD_BUF_SIZE 256
#define BEACON_TAIL_BUF_SIZE 512
head = os_zalloc(BEACON_HEAD_BUF_SIZE);
tail_len = BEACON_TAIL_BUF_SIZE;
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && hapd->wps_beacon_ie)
tail_len += wpabuf_len(hapd->wps_beacon_ie);
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
if (hapd->p2p_beacon_ie)
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
#endif /* CONFIG_P2P */
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
os_free(head);
os_free(tail);
return;
}
head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_BEACON);
head->duration = host_to_le16(0);
os_memset(head->da, 0xff, ETH_ALEN);
os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
head->u.beacon.beacon_int =
host_to_le16(hapd->iconf->beacon_int);
/* hardware or low-level driver will setup seq_ctrl and timestamp */
capab_info = hostapd_own_capab_info(hapd, NULL, 0);
head->u.beacon.capab_info = host_to_le16(capab_info);
pos = &head->u.beacon.variable[0];
/* SSID */
*pos++ = WLAN_EID_SSID;
if (hapd->conf->ignore_broadcast_ssid == 2) {
/* clear the data, but keep the correct length of the SSID */
*pos++ = hapd->conf->ssid.ssid_len;
os_memset(pos, 0, hapd->conf->ssid.ssid_len);
pos += hapd->conf->ssid.ssid_len;
} else if (hapd->conf->ignore_broadcast_ssid) {
*pos++ = 0; /* empty SSID */
} else {
*pos++ = hapd->conf->ssid.ssid_len;
os_memcpy(pos, hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len);
pos += hapd->conf->ssid.ssid_len;
}
/* Supported rates */
pos = hostapd_eid_supp_rates(hapd, pos);
/* DS Params */
pos = hostapd_eid_ds_params(hapd, pos);
head_len = pos - (u8 *) head;
tailpos = hostapd_eid_country(hapd, tailpos,
tail + BEACON_TAIL_BUF_SIZE - tailpos);
/* ERP Information element */
tailpos = hostapd_eid_erp_info(hapd, tailpos);
/* Extended supported rates */
tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
/* RSN, MDIE, WPA */
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos, NULL);
#ifdef CONFIG_IEEE80211N
tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
tailpos = hostapd_eid_ht_operation(hapd, tailpos);
//DRIVER_RTW ADD
if(hapd->iconf->ieee80211n)
hapd->conf->wmm_enabled = 1;
#endif /* CONFIG_IEEE80211N */
tailpos = hostapd_eid_ext_capab(hapd, tailpos);
/* Wi-Fi Alliance WMM */
tailpos = hostapd_eid_wmm(hapd, tailpos);
#ifdef CONFIG_WPS
if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
wpabuf_len(hapd->wps_beacon_ie));
tailpos += wpabuf_len(hapd->wps_beacon_ie);
}
#endif /* CONFIG_WPS */
#ifdef CONFIG_P2P
if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
wpabuf_len(hapd->p2p_beacon_ie));
tailpos += wpabuf_len(hapd->p2p_beacon_ie);
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
P2P_MANAGE)
tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
#endif /* CONFIG_P2P_MANAGER */
tail_len = tailpos > tail ? tailpos - tail : 0;
if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len,
tail, tail_len, hapd->conf->dtim_period,
hapd->iconf->beacon_int))
wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
"period");
os_free(tail);
os_free(head);
#ifdef CONFIG_P2P
no_beacon:
#endif /* CONFIG_P2P */
hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
ERP_INFO_USE_PROTECTION));
}
void ieee802_11_set_beacons(struct hostapd_iface *iface)
{
size_t i;
for (i = 0; i < iface->num_bss; i++)
ieee802_11_set_beacon(iface->bss[i]);
}
#endif /* CONFIG_NATIVE_WINDOWS */

View file

@ -0,0 +1,36 @@
/*
* hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
* Copyright (c) 2002-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef BEACON_H
#define BEACON_H
struct ieee80211_mgmt;
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len);
#ifdef NEED_AP_MLME
void ieee802_11_set_beacon(struct hostapd_data *hapd);
void ieee802_11_set_beacons(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
{
}
static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
{
}
#endif /* NEED_AP_MLME */
#endif /* BEACON_H */

View file

@ -0,0 +1,108 @@
/*
* Control interface for shared AP commands
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "wps_hostapd.h"
#include "p2p_hostapd.h"
#include "ctrl_iface_ap.h"
static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
int len, res, ret;
if (sta == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
len = 0;
ret = os_snprintf(buf + len, buflen - len, MACSTR "\n",
MAC2STR(sta->addr));
if (ret < 0 || (size_t) ret >= buflen - len)
return len;
len += ret;
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
if (res >= 0)
len += res;
res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
buflen - len);
if (res >= 0)
len += res;
res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
return len;
}
int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
}
int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen)
{
u8 addr[ETH_ALEN];
int ret;
if (hwaddr_aton(txtaddr, addr)) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
buf, buflen);
}
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen)
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
int ret;
if (hwaddr_aton(txtaddr, addr) ||
(sta = ap_get_sta(hapd, addr)) == NULL) {
ret = os_snprintf(buf, buflen, "FAIL\n");
if (ret < 0 || (size_t) ret >= buflen)
return 0;
return ret;
}
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}

View file

@ -0,0 +1,25 @@
/*
* Control interface for shared AP commands
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef CTRL_IFACE_AP_H
#define CTRL_IFACE_AP_H
int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
char *buf, size_t buflen);
int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
char *buf, size_t buflen);
#endif /* CTRL_IFACE_AP_H */

View file

@ -0,0 +1,539 @@
/*
* hostapd / Callback functions for driver wrappers
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "radius/radius.h"
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "accounting.h"
#include "tkip_countermeasures.h"
#include "iapp.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
#include "wmm.h"
#include "wps_hostapd.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen, int reassoc)
{
struct sta_info *sta;
int new_assoc, res;
struct ieee802_11_elems elems;
#ifdef CONFIG_P2P
const u8 *all_ies = ie;
size_t all_ies_len = ielen;
#endif /* CONFIG_P2P */
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(ie, ielen, &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) {
accounting_sta_stop(hapd, sta);
} else {
sta = ap_sta_add(hapd, addr);
if (sta == NULL)
return -1;
}
sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
#ifdef CONFIG_P2P
if (elems.p2p) {
wpabuf_free(sta->p2p_ie);
sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len,
P2P_IE_VENDOR_TYPE);
}
#endif /* CONFIG_P2P */
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
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;
}
wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
return -1;
}
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
sta->flags |= WLAN_STA_WPS;
goto skip_wpa_check;
}
if (sta->wpa_sm == NULL)
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->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, NULL, 0);
if (res != WPA_IE_OK) {
int resp;
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
"rejected? (res %u)", res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
if (res == WPA_INVALID_GROUP)
resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
else if (res == WPA_INVALID_PAIRWISE)
resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
else if (res == WPA_INVALID_AKMP)
resp = WLAN_REASON_AKMP_NOT_VALID;
#ifdef CONFIG_IEEE80211W
else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
resp = WLAN_REASON_INVALID_IE;
else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
#endif /* CONFIG_IEEE80211W */
else
resp = WLAN_REASON_INVALID_IE;
hostapd_drv_sta_disassoc(hapd, sta->addr, resp);
ap_free_sta(hapd, sta);
return -1;
}
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS_STRICT
if (ie) {
struct wpabuf *wps;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
if (wps && wps_validate_assoc_req(wps) < 0) {
hostapd_drv_sta_disassoc(
hapd, sta->addr,
WLAN_REASON_INVALID_IE);
ap_free_sta(hapd, sta);
wpabuf_free(wps);
return -1;
}
wpabuf_free(wps);
}
#endif /* CONFIG_WPS_STRICT */
if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
sta->flags |= WLAN_STA_WPS;
} else
sta->flags |= WLAN_STA_MAYBE_WPS;
}
skip_wpa_check:
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
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
p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
all_ies, all_ies_len);
#endif /* CONFIG_P2P */
return 0;
}
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
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 reporting a station mode event while hostapd
* was running, so better make sure we stop processing such an
* event here.
*/
wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
"with no address");
return;
}
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated");
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "Disassociation notification for "
"unknown STA " MACSTR, MAC2STR(addr));
return;
}
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
MAC2STR(sta->addr));
wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
ap_free_sta(hapd, sta);
}
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
if (!sta || !hapd->conf->disassoc_low_ack)
return;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
"missing ACKs");
hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
if (sta)
ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
}
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
const u8 *ie, size_t ie_len)
{
size_t i;
int ret = 0;
if (sa == NULL || ie == NULL)
return -1;
random_add_randomness(sa, ETH_ALEN);
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
sa, ie, ie_len) > 0) {
ret = 1;
break;
}
}
return ret;
}
#ifdef HOSTAPD
#ifdef NEED_AP_MLME
static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
{
u16 fc, type, stype;
/*
* PS-Poll frames are 16 bytes. All other frames are
* 24 bytes or longer.
*/
if (len < 16)
return NULL;
fc = le_to_host16(hdr->frame_control);
type = WLAN_FC_GET_TYPE(fc);
stype = WLAN_FC_GET_STYPE(fc);
switch (type) {
case WLAN_FC_TYPE_DATA:
if (len < 24)
return NULL;
switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
case WLAN_FC_FROMDS | WLAN_FC_TODS:
case WLAN_FC_TODS:
return hdr->addr1;
case WLAN_FC_FROMDS:
return hdr->addr2;
default:
return NULL;
}
case WLAN_FC_TYPE_CTRL:
if (stype != WLAN_FC_STYPE_PSPOLL)
return NULL;
return hdr->addr1;
case WLAN_FC_TYPE_MGMT:
return hdr->addr3;
default:
return NULL;
}
}
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
const u8 *bssid)
{
size_t i;
if (bssid == NULL)
return NULL;
if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
return HAPD_BROADCAST;
for (i = 0; i < iface->num_bss; i++) {
if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
return iface->bss[i];
}
return NULL;
}
static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
const u8 *frame, size_t len)
{
const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
u16 fc = le_to_host16(hdr->frame_control);
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
ieee802_11_rx_from_unknown(hapd, hdr->addr2,
(fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
(WLAN_FC_TODS | WLAN_FC_FROMDS));
}
static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
{
struct hostapd_iface *iface = hapd->iface;
const struct ieee80211_hdr *hdr;
const u8 *bssid;
struct hostapd_frame_info fi;
hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
if (bssid == NULL)
return;
hapd = get_hapd_bssid(iface, bssid);
if (hapd == NULL) {
u16 fc;
fc = le_to_host16(hdr->frame_control);
/*
* Drop frames to unknown BSSIDs except for Beacon frames which
* could be used to update neighbor information.
*/
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
hapd = iface->bss[0];
else
return;
}
os_memset(&fi, 0, sizeof(fi));
fi.datarate = rx_mgmt->datarate;
fi.ssi_signal = rx_mgmt->ssi_signal;
if (hapd == HAPD_BROADCAST) {
size_t i;
for (i = 0; i < iface->num_bss; i++)
ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
rx_mgmt->frame_len, &fi);
} else
ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
random_add_randomness(&fi, sizeof(fi));
}
static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
size_t len, u16 stype, int ok)
{
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *) buf;
hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
if (hapd == NULL || hapd == HAPD_BROADCAST)
return;
ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
}
#endif /* NEED_AP_MLME */
static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta)
return 0;
wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
" - adding a new STA", MAC2STR(addr));
sta = ap_sta_add(hapd, addr);
if (sta) {
hostapd_new_assoc_sta(hapd, sta, 0);
} else {
wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
MAC2STR(addr));
return -1;
}
return 0;
}
static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
const u8 *data, size_t data_len)
{
struct hostapd_iface *iface = hapd->iface;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
if (ap_get_sta(iface->bss[j], src)) {
hapd = iface->bss[j];
break;
}
}
ieee802_1x_receive(hapd, src, data, data_len);
}
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
struct hostapd_data *hapd = ctx;
switch (event) {
case EVENT_MICHAEL_MIC_FAILURE:
michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
break;
case EVENT_SCAN_RESULTS:
if (hapd->iface->scan_cb)
hapd->iface->scan_cb(hapd->iface);
break;
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RRB_RX:
wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
break;
#endif /* CONFIG_IEEE80211R */
case EVENT_WPS_BUTTON_PUSHED:
hostapd_wps_button_pushed(hapd, NULL);
break;
#ifdef NEED_AP_MLME
case EVENT_TX_STATUS:
switch (data->tx_status.type) {
case WLAN_FC_TYPE_MGMT:
hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
data->tx_status.data_len,
data->tx_status.stype,
data->tx_status.ack);
break;
case WLAN_FC_TYPE_DATA:
hostapd_tx_status(hapd, data->tx_status.dst,
data->tx_status.data,
data->tx_status.data_len,
data->tx_status.ack);
break;
}
break;
case EVENT_RX_FROM_UNKNOWN:
hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
data->rx_from_unknown.len);
break;
case EVENT_RX_MGMT:
hostapd_mgmt_rx(hapd, &data->rx_mgmt);
break;
#endif /* NEED_AP_MLME */
case EVENT_RX_PROBE_REQ:
if (data->rx_probe_req.sa == NULL ||
data->rx_probe_req.ie == NULL)
break;
hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
data->rx_probe_req.ie,
data->rx_probe_req.ie_len);
break;
case EVENT_NEW_STA:
hostapd_event_new_sta(hapd, data->new_sta.addr);
break;
case EVENT_EAPOL_RX:
hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
data->eapol_rx.data,
data->eapol_rx.data_len);
break;
case EVENT_ASSOC:
hostapd_notif_assoc(hapd, data->assoc_info.addr,
data->assoc_info.req_ies,
data->assoc_info.req_ies_len,
data->assoc_info.reassoc);
break;
case EVENT_DISASSOC:
if (data)
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
break;
case EVENT_DEAUTH:
if (data)
hostapd_notif_disassoc(hapd, data->deauth_info.addr);
break;
case EVENT_STATION_LOW_ACK:
if (!data)
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
}
}
#endif /* HOSTAPD */

View file

@ -0,0 +1,929 @@
/*
* hostapd / Initialization and configuration
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
#include "accounting.h"
#include "ap_list.h"
#include "beacon.h"
#include "iapp.h"
#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#include "vlan_init.h"
#include "wpa_auth.h"
#include "wps_hostapd.h"
#include "hw_features.h"
#include "wpa_auth_glue.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
static int hostapd_flush_old_stations(struct hostapd_data *hapd);
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
extern int wpa_debug_level;
static void hostapd_reload_bss(struct hostapd_data *hapd)
{
#ifndef CONFIG_NO_RADIUS
radius_client_reconfig(hapd->radius, hapd->conf->radius);
#endif /* CONFIG_NO_RADIUS */
if (hostapd_setup_wpa_psk(hapd->conf)) {
wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
"after reloading configuration");
}
if (hapd->conf->ieee802_1x || hapd->conf->wpa)
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
else
hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
if (hapd->conf->wpa && hapd->wpa_auth == NULL)
hostapd_setup_wpa(hapd);
else if (hapd->conf->wpa) {
const u8 *wpa_ie;
size_t wpa_ie_len;
hostapd_reconfig_wpa(hapd);
wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
"the kernel driver.");
} else if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
hostapd_set_privacy(hapd, 0);
hostapd_setup_encryption(hapd->conf->iface, hapd);
hostapd_set_generic_elem(hapd, (u8 *) "", 0);
}
ieee802_11_set_beacon(hapd);
hostapd_update_wps(hapd);
if (hapd->conf->ssid.ssid_set &&
hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len)) {
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
/* try to continue */
}
wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
}
int hostapd_reload_config(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_config *newconf, *oldconf;
size_t j;
if (iface->config_read_cb == NULL)
return -1;
newconf = iface->config_read_cb(iface->config_fname);
if (newconf == NULL)
return -1;
/*
* Deauthenticate all stations since the new configuration may not
* allow them to use the BSS anymore.
*/
for (j = 0; j < iface->num_bss; j++) {
hostapd_flush_old_stations(iface->bss[j]);
#ifndef CONFIG_NO_RADIUS
/* TODO: update dynamic data based on changed configuration
* items (e.g., open/close sockets, etc.) */
radius_client_flush(iface->bss[j]->radius, 0);
#endif /* CONFIG_NO_RADIUS */
}
oldconf = hapd->iconf;
iface->conf = newconf;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
hapd->iconf = newconf;
hapd->conf = &newconf->bss[j];
hostapd_reload_bss(hapd);
}
hostapd_config_free(oldconf);
return 0;
}
static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
char *ifname)
{
int i;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
0, NULL, 0, NULL, 0)) {
wpa_printf(MSG_DEBUG, "Failed to clear default "
"encryption keys (ifname=%s keyidx=%d)",
ifname, i);
}
}
#ifdef CONFIG_IEEE80211W
if (hapd->conf->ieee80211w) {
for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
NULL, i, 0, NULL,
0, NULL, 0)) {
wpa_printf(MSG_DEBUG, "Failed to clear "
"default mgmt encryption keys "
"(ifname=%s keyidx=%d)", ifname, i);
}
}
}
#endif /* CONFIG_IEEE80211W */
}
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
{
hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
return 0;
}
static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
{
int errors = 0, idx;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
idx = ssid->wep.idx;
if (ssid->wep.default_len &&
hostapd_drv_set_key(hapd->conf->iface,
hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
1, NULL, 0, ssid->wep.key[idx],
ssid->wep.len[idx])) {
wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
errors++;
}
if (ssid->dyn_vlan_keys) {
size_t i;
for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
const char *ifname;
struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
if (key == NULL)
continue;
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
i);
if (ifname == NULL)
continue;
idx = key->idx;
if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
broadcast_ether_addr, idx, 1,
NULL, 0, key->key[idx],
key->len[idx])) {
wpa_printf(MSG_WARNING, "Could not set "
"dynamic VLAN WEP encryption.");
errors++;
}
}
}
return errors;
}
/**
* hostapd_cleanup - Per-BSS cleanup (deinitialization)
* @hapd: Pointer to BSS data
*
* This function is used to free all per-BSS data structures and resources.
* This gets called in a loop for each BSS between calls to
* hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
* is deinitialized. Most of the modules that are initialized in
* hostapd_setup_bss() are deinitialized here.
*/
static void hostapd_cleanup(struct hostapd_data *hapd)
{
if (hapd->iface->ctrl_iface_deinit)
hapd->iface->ctrl_iface_deinit(hapd);
iapp_deinit(hapd->iapp);
hapd->iapp = NULL;
accounting_deinit(hapd);
hostapd_deinit_wpa(hapd);
vlan_deinit(hapd);
hostapd_acl_deinit(hapd);
#ifndef CONFIG_NO_RADIUS
radius_client_deinit(hapd->radius);
hapd->radius = NULL;
#endif /* CONFIG_NO_RADIUS */
hostapd_deinit_wps(hapd);
authsrv_deinit(hapd);
if (hapd->interface_added &&
hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
hapd->conf->iface);
}
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
#ifdef CONFIG_P2P
wpabuf_free(hapd->p2p_beacon_ie);
hapd->p2p_beacon_ie = NULL;
wpabuf_free(hapd->p2p_probe_resp_ie);
hapd->p2p_probe_resp_ie = NULL;
#endif /* CONFIG_P2P */
}
/**
* hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
* @iface: Pointer to interface data
*
* This function is called before per-BSS data structures are deinitialized
* with hostapd_cleanup().
*/
static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
{
}
/**
* hostapd_cleanup_iface - Complete per-interface cleanup
* @iface: Pointer to interface data
*
* This function is called after per-BSS data structures are deinitialized
* with hostapd_cleanup().
*/
static void hostapd_cleanup_iface(struct hostapd_iface *iface)
{
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = NULL;
os_free(iface->current_rates);
iface->current_rates = NULL;
ap_list_deinit(iface);
hostapd_config_free(iface->conf);
iface->conf = NULL;
os_free(iface->config_fname);
os_free(iface->bss);
os_free(iface);
}
static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
{
int i;
hostapd_broadcast_wep_set(hapd);
if (hapd->conf->ssid.wep.default_len) {
hostapd_set_privacy(hapd, 1);
return 0;
}
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
hapd->conf->ssid.wep.len[i])) {
wpa_printf(MSG_WARNING, "Could not set WEP "
"encryption.");
return -1;
}
if (hapd->conf->ssid.wep.key[i] &&
i == hapd->conf->ssid.wep.idx)
hostapd_set_privacy(hapd, 1);
}
return 0;
}
static int hostapd_flush_old_stations(struct hostapd_data *hapd)
{
int ret = 0;
u8 addr[ETH_ALEN];
if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
return 0;
wpa_printf(MSG_DEBUG, "Flushing old station entries");
if (hostapd_flush(hapd)) {
wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
ret = -1;
}
wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
os_memset(addr, 0xff, ETH_ALEN);
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_free_stas(hapd);
return ret;
}
/**
* hostapd_validate_bssid_configuration - Validate BSSID configuration
* @iface: Pointer to interface data
* Returns: 0 on success, -1 on failure
*
* This function is used to validate that the configured BSSIDs are valid.
*/
static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
{
u8 mask[ETH_ALEN] = { 0 };
struct hostapd_data *hapd = iface->bss[0];
unsigned int i = iface->conf->num_bss, bits = 0, j;
int res;
int auto_addr = 0;
if (hostapd_drv_none(hapd))
return 0;
/* Generate BSSID mask that is large enough to cover the BSSIDs. */
/* Determine the bits necessary to cover the number of BSSIDs. */
for (i--; i; i >>= 1)
bits++;
/* Determine the bits necessary to any configured BSSIDs,
if they are higher than the number of BSSIDs. */
for (j = 0; j < iface->conf->num_bss; j++) {
if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
if (j)
auto_addr++;
continue;
}
for (i = 0; i < ETH_ALEN; i++) {
mask[i] |=
iface->conf->bss[j].bssid[i] ^
hapd->own_addr[i];
}
}
if (!auto_addr)
goto skip_mask_ext;
for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
;
j = 0;
if (i < ETH_ALEN) {
j = (5 - i) * 8;
while (mask[i] != 0) {
mask[i] >>= 1;
j++;
}
}
if (bits < j)
bits = j;
if (bits > 40) {
wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
bits);
return -1;
}
os_memset(mask, 0xff, ETH_ALEN);
j = bits / 8;
for (i = 5; i > 5 - j; i--)
mask[i] = 0;
j = bits % 8;
while (j--)
mask[i] <<= 1;
skip_mask_ext:
wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
(unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
if (res == 0)
return 0;
if (res < 0) {
wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
MACSTR " for start address " MACSTR ".",
MAC2STR(mask), MAC2STR(hapd->own_addr));
return -1;
}
if (!auto_addr)
return 0;
for (i = 0; i < ETH_ALEN; i++) {
if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
" for start address " MACSTR ".",
MAC2STR(mask), MAC2STR(hapd->own_addr));
wpa_printf(MSG_ERROR, "Start address must be the "
"first address in the block (i.e., addr "
"AND mask == addr).");
return -1;
}
}
return 0;
}
static int mac_in_conf(struct hostapd_config *conf, const void *a)
{
size_t i;
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
return 1;
}
}
return 0;
}
/**
* hostapd_setup_bss - Per-BSS setup (initialization)
* @hapd: Pointer to BSS data
* @first: Whether this BSS is the first BSS of an interface
*
* This function is used to initialize all per-BSS data structures and
* resources. This gets called in a loop for each BSS when an interface is
* initialized. Most of the modules that are initialized here will be
* deinitialized in hostapd_cleanup().
*/
static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
{
struct hostapd_bss_config *conf = hapd->conf;
u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
if (!first) {
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
/* Allocate the next available BSSID. */
do {
inc_byte_array(hapd->own_addr, ETH_ALEN);
} while (mac_in_conf(hapd->iconf, hapd->own_addr));
} else {
/* Allocate the configured BSSID. */
os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
if (hostapd_mac_comp(hapd->own_addr,
hapd->iface->bss[0]->own_addr) ==
0) {
wpa_printf(MSG_ERROR, "BSS '%s' may not have "
"BSSID set to the MAC address of "
"the radio", hapd->conf->iface);
return -1;
}
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
hapd->conf->iface, hapd->own_addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
hapd->conf->bridge[0] ? hapd->conf->bridge :
NULL)) {
wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
MACSTR ")", MAC2STR(hapd->own_addr));
return -1;
}
}
if (conf->wmm_enabled < 0)
conf->wmm_enabled = hapd->iconf->ieee80211n;
hostapd_flush_old_stations(hapd);
hostapd_set_privacy(hapd, 0);
hostapd_broadcast_wep_clear(hapd);
if (hostapd_setup_encryption(hapd->conf->iface, hapd))
return -1;
/*
* Fetch the SSID from the system and use it or,
* if one was specified in the config file, verify they
* match.
*/
ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
if (ssid_len < 0) {
wpa_printf(MSG_ERROR, "Could not read SSID from system");
return -1;
}
if (conf->ssid.ssid_set) {
/*
* If SSID is specified in the config file and it differs
* from what is being used then force installation of the
* new SSID.
*/
set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
} else {
/*
* No SSID in the config file; just use the one we got
* from the system.
*/
set_ssid = 0;
conf->ssid.ssid_len = ssid_len;
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
}
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
" and ssid '%s'",
hapd->conf->iface, MAC2STR(hapd->own_addr),
hapd->conf->ssid.ssid);
}
if (hostapd_setup_wpa_psk(conf)) {
wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
return -1;
}
/* Set SSID for the kernel driver (to be used in beacon and probe
* response frames) */
if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
conf->ssid.ssid_len)) {
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
return -1;
}
if (wpa_debug_level == MSG_MSGDUMP)
conf->radius->msg_dumps = 1;
#ifndef CONFIG_NO_RADIUS
hapd->radius = radius_client_init(hapd, conf->radius);
if (hapd->radius == NULL) {
wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
return -1;
}
#endif /* CONFIG_NO_RADIUS */
if (hostapd_acl_init(hapd)) {
wpa_printf(MSG_ERROR, "ACL initialization failed.");
return -1;
}
if (hostapd_init_wps(hapd, conf))
return -1;
if (authsrv_init(hapd) < 0)
return -1;
if (ieee802_1x_init(hapd)) {
wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
return -1;
}
if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
return -1;
if (accounting_init(hapd)) {
wpa_printf(MSG_ERROR, "Accounting initialization failed.");
return -1;
}
if (hapd->conf->ieee802_11f &&
(hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
"failed.");
return -1;
}
if (hapd->iface->ctrl_iface_init &&
hapd->iface->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR, "Failed to setup control interface");
return -1;
}
if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
wpa_printf(MSG_ERROR, "VLAN initialization failed.");
return -1;
}
ieee802_11_set_beacon(hapd);
if (hapd->driver && hapd->driver->set_operstate)
hapd->driver->set_operstate(hapd->drv_priv, 1);
return 0;
}
static void hostapd_tx_queue_params(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
int i;
struct hostapd_tx_queue_params *p;
for (i = 0; i < NUM_TX_QUEUES; i++) {
p = &iface->conf->tx_queue[i];
if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
p->cwmax, p->burst)) {
wpa_printf(MSG_DEBUG, "Failed to set TX queue "
"parameters for queue %d.", i);
/* Continue anyway */
}
}
}
static int setup_interface(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
size_t i;
char country[4];
/*
* Make sure that all BSSes get configured with a pointer to the same
* driver interface.
*/
for (i = 1; i < iface->num_bss; i++) {
iface->bss[i]->driver = hapd->driver;
iface->bss[i]->drv_priv = hapd->drv_priv;
}
if (hostapd_validate_bssid_configuration(iface))
return -1;
if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
os_memcpy(country, hapd->iconf->country, 3);
country[3] = '\0';
if (hostapd_set_country(hapd, country) < 0) {
wpa_printf(MSG_ERROR, "Failed to set country code");
return -1;
}
}
if (hostapd_get_hw_features(iface)) {
/* Not all drivers support this yet, so continue without hw
* feature data. */
} else {
int ret = hostapd_select_hw_mode(iface);
if (ret < 0) {
wpa_printf(MSG_ERROR, "Could not select hw_mode and "
"channel. (%d)", ret);
return -1;
}
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
return -1;
if (ret == 1) {
wpa_printf(MSG_DEBUG, "Interface initialization will "
"be completed in a callback");
return 0;
}
}
return hostapd_setup_interface_complete(iface, 0);
}
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
{
struct hostapd_data *hapd = iface->bss[0];
size_t j;
u8 *prev_addr;
if (err) {
wpa_printf(MSG_ERROR, "Interface initialization failed");
eloop_terminate();
return -1;
}
wpa_printf(MSG_DEBUG, "Completing interface initialization");
if (hapd->iconf->channel) {
iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
"Frequency: %d MHz",
hostapd_hw_mode_txt(hapd->iconf->hw_mode),
hapd->iconf->channel, iface->freq);
if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
hapd->iconf->ieee80211n,
hapd->iconf->secondary_channel)) {
wpa_printf(MSG_ERROR, "Could not set channel for "
"kernel driver");
return -1;
}
}
if (iface->current_mode) {
if (hostapd_prepare_rates(hapd, iface->current_mode)) {
wpa_printf(MSG_ERROR, "Failed to prepare rates "
"table.");
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Failed to prepare rates table.");
return -1;
}
}
if (hapd->iconf->rts_threshold > -1 &&
hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
"kernel driver");
return -1;
}
if (hapd->iconf->fragm_threshold > -1 &&
hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
"for kernel driver");
return -1;
}
prev_addr = hapd->own_addr;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
if (j)
os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
if (hostapd_setup_bss(hapd, j == 0))
return -1;
if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
prev_addr = hapd->own_addr;
}
hostapd_tx_queue_params(iface);
ap_list_init(iface);
if (hostapd_driver_commit(hapd) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
"configuration", __func__);
return -1;
}
if (hapd->setup_complete_cb)
hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
iface->bss[0]->conf->iface);
return 0;
}
/**
* hostapd_setup_interface - Setup of an interface
* @iface: Pointer to interface data.
* Returns: 0 on success, -1 on failure
*
* Initializes the driver interface, validates the configuration,
* and sets driver parameters based on the configuration.
* Flushes old stations, sets the channel, encryption,
* beacons, and WDS links based on the configuration.
*/
int hostapd_setup_interface(struct hostapd_iface *iface)
{
int ret;
ret = setup_interface(iface);
if (ret) {
wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
iface->bss[0]->conf->iface);
return -1;
}
return 0;
}
/**
* hostapd_alloc_bss_data - Allocate and initialize per-BSS data
* @hapd_iface: Pointer to interface data
* @conf: Pointer to per-interface configuration
* @bss: Pointer to per-BSS configuration for this BSS
* Returns: Pointer to allocated BSS data
*
* This function is used to allocate per-BSS data structure. This data will be
* freed after hostapd_cleanup() is called for it during interface
* deinitialization.
*/
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
struct hostapd_config *conf,
struct hostapd_bss_config *bss)
{
struct hostapd_data *hapd;
hapd = os_zalloc(sizeof(*hapd));
if (hapd == NULL)
return NULL;
hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
hapd->iconf = conf;
hapd->conf = bss;
hapd->iface = hapd_iface;
hapd->driver = hapd->iconf->driver;
return hapd;
}
void hostapd_interface_deinit(struct hostapd_iface *iface)
{
size_t j;
if (iface == NULL)
return;
hostapd_cleanup_iface_pre(iface);
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
hostapd_free_stas(hapd);
hostapd_flush_old_stations(hapd);
hostapd_cleanup(hapd);
}
}
void hostapd_interface_free(struct hostapd_iface *iface)
{
size_t j;
for (j = 0; j < iface->num_bss; j++)
os_free(iface->bss[j]);
hostapd_cleanup_iface(iface);
}
/**
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
* @hapd: Pointer to BSS data
* @sta: Pointer to the associated STA data
* @reassoc: 1 to indicate this was a re-association; 0 = first association
*
* This function will be called whenever a station associates with the AP. It
* can be called from ieee802_11.c for drivers that export MLME to hostapd and
* from drv_callbacks.c based on driver events for drivers that take care of
* management frames (IEEE 802.11 authentication and association) internally.
*/
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc)
{
if (hapd->tkip_countermeasures) {
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_MICHAEL_MIC_FAILURE);
return;
}
hostapd_prune_associations(hapd, sta->addr);
/* IEEE 802.11F (IAPP) */
if (hapd->conf->ieee802_11f)
iapp_new_station(hapd->iapp, sta);
#ifdef CONFIG_P2P
if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
sta->no_p2p_set = 1;
hapd->num_sta_no_p2p++;
if (hapd->num_sta_no_p2p == 1)
hostapd_p2p_non_p2p_sta_connected(hapd);
}
#endif /* CONFIG_P2P */
/* Start accounting here, if IEEE 802.1X and WPA are not used.
* IEEE 802.1X/WPA code will start accounting after the station has
* been authorized. */
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
accounting_sta_start(hapd, sta);
/* Start IEEE 802.1X authentication process for new stations */
ieee802_1x_new_station(hapd, sta);
if (reassoc) {
if (sta->auth_alg != WLAN_AUTH_FT &&
!(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
} else
wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
}

View file

@ -0,0 +1,262 @@
/*
* hostapd / Initialization and configuration
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef HOSTAPD_H
#define HOSTAPD_H
#include "common/defs.h"
struct wpa_driver_ops;
struct wpa_ctrl_dst;
struct radius_server_data;
struct upnp_wps_device_sm;
struct hapd_interfaces;
struct hostapd_data;
struct sta_info;
struct hostap_sta_driver_data;
struct ieee80211_ht_capabilities;
struct full_dynamic_vlan;
enum wps_event;
union wps_event_data;
struct hostapd_probereq_cb {
int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
void *ctx;
};
#define HOSTAPD_RATE_BASIC 0x00000001
struct hostapd_rate_data {
int rate; /* rate in 100 kbps */
int flags; /* HOSTAPD_RATE_ flags */
};
struct hostapd_frame_info {
u32 channel;
u32 datarate;
u32 ssi_signal;
};
/**
* struct hostapd_data - hostapd per-BSS data structure
*/
struct hostapd_data {
struct hostapd_iface *iface;
struct hostapd_config *iconf;
struct hostapd_bss_config *conf;
int interface_added; /* virtual interface added for this BSS */
u8 own_addr[ETH_ALEN];
int num_sta; /* number of entries in sta_list */
struct sta_info *sta_list; /* STA info list head */
#define STA_HASH_SIZE 256
#define STA_HASH(sta) (sta[5])
struct sta_info *sta_hash[STA_HASH_SIZE];
/*
* Bitfield for indicating which AIDs are allocated. Only AID values
* 1-2007 are used and as such, the bit at index 0 corresponds to AID
* 1.
*/
#define AID_WORDS ((2008 + 31) / 32)
u32 sta_aid[AID_WORDS];
const struct wpa_driver_ops *driver;
void *drv_priv;
void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
struct sta_info *sta, int reassoc);
void *msg_ctx; /* ctx for wpa_msg() calls */
struct radius_client_data *radius;
u32 acct_session_id_hi, acct_session_id_lo;
struct iapp_data *iapp;
struct hostapd_cached_radius_acl *acl_cache;
struct hostapd_acl_query_data *acl_queries;
struct wpa_authenticator *wpa_auth;
struct eapol_authenticator *eapol_auth;
struct rsn_preauth_interface *preauth_iface;
time_t michael_mic_failure;
int michael_mic_failures;
int tkip_countermeasures;
int ctrl_sock;
struct wpa_ctrl_dst *ctrl_dst;
void *ssl_ctx;
void *eap_sim_db_priv;
struct radius_server_data *radius_srv;
int parameter_set_count;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
struct full_dynamic_vlan *full_dynamic_vlan;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
struct l2_packet_data *l2;
struct wps_context *wps;
struct wpabuf *wps_beacon_ie;
struct wpabuf *wps_probe_resp_ie;
#ifdef CONFIG_WPS
unsigned int ap_pin_failures;
struct upnp_wps_device_sm *wps_upnp;
unsigned int ap_pin_lockout_time;
#endif /* CONFIG_WPS */
struct hostapd_probereq_cb *probereq_cb;
size_t num_probereq_cb;
void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
void *public_action_cb_ctx;
int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
int freq);
void *vendor_action_cb_ctx;
void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
const u8 *uuid_e);
void *wps_reg_success_cb_ctx;
void (*wps_event_cb)(void *ctx, enum wps_event event,
union wps_event_data *data);
void *wps_event_cb_ctx;
void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
int authorized);
void *sta_authorized_cb_ctx;
void (*setup_complete_cb)(void *ctx);
void *setup_complete_cb_ctx;
#ifdef CONFIG_P2P
struct p2p_data *p2p;
struct p2p_group *p2p_group;
struct wpabuf *p2p_beacon_ie;
struct wpabuf *p2p_probe_resp_ie;
/* Number of non-P2P association stations */
int num_sta_no_p2p;
/* Periodic NoA (used only when no non-P2P clients in the group) */
int noa_enabled;
int noa_start;
int noa_duration;
#endif /* CONFIG_P2P */
};
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
struct hostapd_iface {
struct hapd_interfaces *interfaces;
void *owner;
int (*reload_config)(struct hostapd_iface *iface);
struct hostapd_config * (*config_read_cb)(const char *config_fname);
char *config_fname;
struct hostapd_config *conf;
size_t num_bss;
struct hostapd_data **bss;
int num_ap; /* number of entries in ap_list */
struct ap_info *ap_list; /* AP info list head */
struct ap_info *ap_hash[STA_HASH_SIZE];
struct ap_info *ap_iter_list;
unsigned int drv_flags;
struct hostapd_hw_modes *hw_features;
int num_hw_features;
struct hostapd_hw_modes *current_mode;
/* Rates that are currently used (i.e., filtered copy of
* current_mode->channels */
int num_rates;
struct hostapd_rate_data *current_rates;
int freq;
u16 hw_flags;
/* Number of associated Non-ERP stations (i.e., stations using 802.11b
* in 802.11g BSS) */
int num_sta_non_erp;
/* Number of associated stations that do not support Short Slot Time */
int num_sta_no_short_slot_time;
/* Number of associated stations that do not support Short Preamble */
int num_sta_no_short_preamble;
int olbc; /* Overlapping Legacy BSS Condition */
/* Number of HT associated stations that do not support greenfield */
int num_sta_ht_no_gf;
/* Number of associated non-HT stations */
int num_sta_no_ht;
/* Number of HT associated stations 20 MHz */
int num_sta_ht_20mhz;
/* Overlapping BSS information */
int olbc_ht;
u16 ht_op_mode;
void (*scan_cb)(struct hostapd_iface *iface);
int (*ctrl_iface_init)(struct hostapd_data *hapd);
void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
int (*for_each_interface)(struct hapd_interfaces *interfaces,
int (*cb)(struct hostapd_iface *iface,
void *ctx), void *ctx);
};
/* hostapd.c */
int hostapd_reload_config(struct hostapd_iface *iface);
struct hostapd_data *
hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
struct hostapd_config *conf,
struct hostapd_bss_config *bss);
int hostapd_setup_interface(struct hostapd_iface *iface);
int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
void hostapd_interface_deinit(struct hostapd_iface *iface);
void hostapd_interface_free(struct hostapd_iface *iface);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *ie, size_t ie_len),
void *ctx);
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
/* drv_callbacks.c (TODO: move to somewhere else?) */
int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ielen, int reassoc);
void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
const u8 *ie, size_t ie_len);
#endif /* HOSTAPD_H */

View file

@ -0,0 +1,754 @@
/*
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "hw_features.h"
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features)
{
size_t i;
if (hw_features == NULL)
return;
for (i = 0; i < num_hw_features; i++) {
os_free(hw_features[i].channels);
os_free(hw_features[i].rates);
}
os_free(hw_features);
}
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
int ret = 0, i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
if (hostapd_drv_none(hapd))
return -1;
modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
if (modes == NULL) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"Fetching hardware channel/rate support not "
"supported.");
return -1;
}
iface->hw_flags = flags;
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = modes;
iface->num_hw_features = num_modes;
for (i = 0; i < num_modes; i++) {
struct hostapd_hw_modes *feature = &modes[i];
/* set flag for channels we can use in current regulatory
* domain */
for (j = 0; j < feature->num_channels; j++) {
/*
* Disable all channels that are marked not to allow
* IBSS operation or active scanning. In addition,
* disable all channels that require radar detection,
* since that (in addition to full DFS) is not yet
* supported.
*/
if (feature->channels[j].flag &
(HOSTAPD_CHAN_NO_IBSS |
HOSTAPD_CHAN_PASSIVE_SCAN |
HOSTAPD_CHAN_RADAR))
feature->channels[j].flag |=
HOSTAPD_CHAN_DISABLED;
if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
"chan=%d freq=%d MHz max_tx_power=%d dBm",
feature->mode,
feature->channels[j].chan,
feature->channels[j].freq,
feature->channels[j].max_tx_power);
}
}
return ret;
}
int hostapd_prepare_rates(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode)
{
int i, num_basic_rates = 0;
int basic_rates_a[] = { 60, 120, 240, -1 };
int basic_rates_b[] = { 10, 20, -1 };
int basic_rates_g[] = { 10, 20, 55, 110, -1 };
int *basic_rates;
if (hapd->iconf->basic_rates)
basic_rates = hapd->iconf->basic_rates;
else switch (mode->mode) {
case HOSTAPD_MODE_IEEE80211A:
basic_rates = basic_rates_a;
break;
case HOSTAPD_MODE_IEEE80211B:
basic_rates = basic_rates_b;
break;
case HOSTAPD_MODE_IEEE80211G:
basic_rates = basic_rates_g;
break;
default:
return -1;
}
if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
basic_rates, mode->mode)) {
wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
"module");
}
os_free(hapd->iface->current_rates);
hapd->iface->num_rates = 0;
hapd->iface->current_rates =
os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
if (!hapd->iface->current_rates) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
"table.");
return -1;
}
for (i = 0; i < mode->num_rates; i++) {
struct hostapd_rate_data *rate;
if (hapd->iconf->supported_rates &&
!hostapd_rate_found(hapd->iconf->supported_rates,
mode->rates[i]))
continue;
rate = &hapd->iface->current_rates[hapd->iface->num_rates];
rate->rate = mode->rates[i];
if (hostapd_rate_found(basic_rates, rate->rate)) {
rate->flags |= HOSTAPD_RATE_BASIC;
num_basic_rates++;
}
wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
hapd->iface->num_rates, rate->rate, rate->flags);
hapd->iface->num_rates++;
}
if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) &&
(!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) {
wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
"rate sets (%d,%d).",
hapd->iface->num_rates, num_basic_rates);
return -1;
}
return 0;
}
#ifdef CONFIG_IEEE80211N
static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
{
int sec_chan, ok, j, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
184, 192 };
size_t k;
if (!iface->conf->secondary_channel)
return 1; /* HT40 not used */
sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
wpa_printf(MSG_DEBUG, "HT40: control channel: %d "
"secondary channel: %d",
iface->conf->channel, sec_chan);
/* Verify that HT40 secondary channel is an allowed 20 MHz
* channel */
ok = 0;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
chan->chan == sec_chan) {
ok = 1;
break;
}
}
if (!ok) {
wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
sec_chan);
return 0;
}
/*
* Verify that HT40 primary,secondary channel pair is allowed per
* IEEE 802.11n Annex J. This is only needed for 5 GHz band since
* 2.4 GHz rules allow all cases where the secondary channel fits into
* the list of allowed channels (already checked above).
*/
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
return 1;
if (iface->conf->secondary_channel > 0)
first = iface->conf->channel;
else
first = sec_chan;
ok = 0;
for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
if (first == allowed[k]) {
ok = 1;
break;
}
}
if (!ok) {
wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
iface->conf->channel,
iface->conf->secondary_channel);
return 0;
}
return 1;
}
static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
{
if (iface->conf->secondary_channel > 0) {
iface->conf->channel += 4;
iface->conf->secondary_channel = -1;
} else {
iface->conf->channel -= 4;
iface->conf->secondary_channel = 1;
}
}
static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
int *pri_chan, int *sec_chan)
{
struct ieee80211_ht_operation *oper;
struct ieee802_11_elems elems;
*pri_chan = *sec_chan = 0;
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
if (elems.ht_operation &&
elems.ht_operation_len >= sizeof(*oper)) {
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
*pri_chan = oper->control_chan;
if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
int sec = oper->ht_param &
HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
*sec_chan = *pri_chan + 4;
else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
*sec_chan = *pri_chan - 4;
}
}
}
static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
int bss_pri_chan, bss_sec_chan;
size_t i;
int match;
pri_chan = iface->conf->channel;
sec_chan = iface->conf->secondary_channel * 4;
pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
sec_freq = pri_freq - 20;
/*
* Switch PRI/SEC channels if Beacons were detected on selected SEC
* channel, but not on selected PRI channel.
*/
pri_bss = sec_bss = 0;
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
if (bss->freq == pri_freq)
pri_bss++;
else if (bss->freq == sec_freq)
sec_bss++;
}
if (sec_bss && !pri_bss) {
wpa_printf(MSG_INFO, "Switch own primary and secondary "
"channel to get secondary channel with no Beacons "
"from other BSSes");
ieee80211n_switch_pri_sec(iface);
}
/*
* Match PRI/SEC channel with any existing HT40 BSS on the same
* channels that we are about to use (if already mixed order in
* existing BSSes, use own preference).
*/
match = 0;
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
if (pri_chan == bss_pri_chan &&
sec_chan == bss_sec_chan) {
match = 1;
break;
}
}
if (!match) {
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
&bss_sec_chan);
if (pri_chan == bss_sec_chan &&
sec_chan == bss_pri_chan) {
wpa_printf(MSG_INFO, "Switch own primary and "
"secondary channel due to BSS "
"overlap with " MACSTR,
MAC2STR(bss->bssid));
ieee80211n_switch_pri_sec(iface);
break;
}
}
}
return 1;
}
static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
struct wpa_scan_results *scan_res)
{
int pri_freq, sec_freq;
int affected_start, affected_end;
size_t i;
pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
if (iface->conf->secondary_channel > 0)
sec_freq = pri_freq + 20;
else
sec_freq = pri_freq - 20;
affected_start = (pri_freq + sec_freq) / 2 - 25;
affected_end = (pri_freq + sec_freq) / 2 + 25;
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
affected_start, affected_end);
for (i = 0; i < scan_res->num; i++) {
struct wpa_scan_res *bss = scan_res->res[i];
int pri = bss->freq;
int sec = pri;
int sec_chan, pri_chan;
ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
if (sec_chan) {
if (sec_chan < pri_chan)
sec = pri - 20;
else
sec = pri + 20;
}
if ((pri < affected_start || pri > affected_end) &&
(sec < affected_start || sec > affected_end))
continue; /* not within affected channel range */
wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
" freq=%d pri=%d sec=%d",
MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
if (sec_chan) {
if (pri_freq != pri || sec_freq != sec) {
wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
"mismatch with BSS " MACSTR
" <%d,%d> (chan=%d%c) vs. <%d,%d>",
MAC2STR(bss->bssid),
pri, sec, pri_chan,
sec > pri ? '+' : '-',
pri_freq, sec_freq);
return 0;
}
}
/* TODO: 40 MHz intolerant */
}
return 1;
}
static void wpa_scan_results_free(struct wpa_scan_results *res)
{
size_t i;
if (res == NULL)
return;
for (i = 0; i < res->num; i++)
os_free(res->res[i]);
os_free(res->res);
os_free(res);
}
static void ieee80211n_check_scan(struct hostapd_iface *iface)
{
struct wpa_scan_results *scan_res;
int oper40;
int res;
/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
* allowed per IEEE 802.11n/D7.0, 11.14.3.2 */
iface->scan_cb = NULL;
scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
if (scan_res == NULL) {
hostapd_setup_interface_complete(iface, 1);
return;
}
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
else
oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
wpa_scan_results_free(scan_res);
if (!oper40) {
wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
"channel pri=%d sec=%d based on overlapping BSSes",
iface->conf->channel,
iface->conf->channel +
iface->conf->secondary_channel * 4);
iface->conf->secondary_channel = 0;
iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
}
res = ieee80211n_allowed_ht40_channel_pair(iface);
hostapd_setup_interface_complete(iface, !res);
}
static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
{
struct wpa_driver_scan_params params;
if (!iface->conf->secondary_channel)
return 0; /* HT40 not used */
wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
"40 MHz channel");
os_memset(&params, 0, sizeof(params));
/* TODO: scan only the needed frequency */
if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
wpa_printf(MSG_ERROR, "Failed to request a scan of "
"neighboring BSSes");
//DRIVER_RTW Modify
//return -1;
return 0;//ignore this error
}
iface->scan_cb = ieee80211n_check_scan;
return 1;
}
static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
{
u16 hw = iface->current_mode->ht_capab;
u16 conf = iface->conf->ht_capab;
if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
!(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [LDPC]");
return 0;
}
if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
!(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [HT40*]");
return 0;
}
if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
(conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SMPS-*]");
return 0;
}
if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
!(hw & HT_CAP_INFO_GREEN_FIELD)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [GF]");
return 0;
}
if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
!(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SHORT-GI-20]");
return 0;
}
if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
!(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [SHORT-GI-40]");
return 0;
}
if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [TX-STBC]");
return 0;
}
if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
(hw & HT_CAP_INFO_RX_STBC_MASK)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [RX-STBC*]");
return 0;
}
if ((conf & HT_CAP_INFO_DELAYED_BA) &&
!(hw & HT_CAP_INFO_DELAYED_BA)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [DELAYED-BA]");
return 0;
}
if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
!(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [MAX-AMSDU-7935]");
return 0;
}
if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
!(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [DSSS_CCK-40]");
return 0;
}
if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [PSMP]");
return 0;
}
if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
!(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
wpa_printf(MSG_ERROR, "Driver does not support configured "
"HT capability [LSIG-TXOP-PROT]");
return 0;
}
return 1;
}
#endif /* CONFIG_IEEE80211N */
int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
#ifdef CONFIG_IEEE80211N
int ret;
if (!iface->conf->ieee80211n)
return 0;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
ret = ieee80211n_check_40mhz(iface);
if (ret)
return ret;
if (!ieee80211n_allowed_ht40_channel_pair(iface))
return -1;
#endif /* CONFIG_IEEE80211N */
return 0;
}
/**
* hostapd_select_hw_mode - Select the hardware mode
* @iface: Pointer to interface data.
* Returns: 0 on success, -1 on failure
*
* Sets up the hardware mode, channel, rates, and passive scanning
* based on the configuration.
*/
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
int i, j, ok;
if (iface->num_hw_features < 1)
return -1;
iface->current_mode = NULL;
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
if (mode->mode == iface->conf->hw_mode) {
iface->current_mode = mode;
break;
}
}
if (iface->current_mode == NULL) {
wpa_printf(MSG_ERROR, "Hardware does not support configured "
"mode");
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured mode "
"(%d)", (int) iface->conf->hw_mode);
return -1;
}
ok = 0;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
(chan->chan == iface->conf->channel)) {
ok = 1;
break;
}
}
if (ok && iface->conf->secondary_channel) {
int sec_ok = 0;
int sec_chan = iface->conf->channel +
iface->conf->secondary_channel * 4;
for (j = 0; j < iface->current_mode->num_channels; j++) {
struct hostapd_channel_data *chan =
&iface->current_mode->channels[j];
if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
(chan->chan == sec_chan)) {
sec_ok = 1;
break;
}
}
if (!sec_ok) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured HT40 secondary channel "
"(%d) not found from the channel list "
"of current mode (%d) %s",
sec_chan, iface->current_mode->mode,
hostapd_hw_mode_txt(
iface->current_mode->mode));
ok = 0;
}
}
if (iface->conf->channel == 0) {
/* TODO: could request a scan of neighboring BSSes and select
* the channel automatically */
wpa_printf(MSG_ERROR, "Channel not configured "
"(hw_mode/channel in hostapd.conf)");
return -1;
}
if (ok == 0 && iface->conf->channel != 0) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Configured channel (%d) not found from the "
"channel list of current mode (%d) %s",
iface->conf->channel,
iface->current_mode->mode,
hostapd_hw_mode_txt(iface->current_mode->mode));
iface->current_mode = NULL;
}
if (iface->current_mode == NULL) {
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured channel");
return -1;
}
return 0;
}
const char * hostapd_hw_mode_txt(int mode)
{
switch (mode) {
case HOSTAPD_MODE_IEEE80211A:
return "IEEE 802.11a";
case HOSTAPD_MODE_IEEE80211B:
return "IEEE 802.11b";
case HOSTAPD_MODE_IEEE80211G:
return "IEEE 802.11g";
default:
return "UNKNOWN";
}
}
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
{
int i;
if (!hapd->iface->current_mode)
return 0;
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
struct hostapd_channel_data *ch =
&hapd->iface->current_mode->channels[i];
if (ch->chan == chan)
return ch->freq;
}
return 0;
}
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
{
int i;
if (!hapd->iface->current_mode)
return 0;
for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
struct hostapd_channel_data *ch =
&hapd->iface->current_mode->channels[i];
if (ch->freq == freq)
return ch->chan;
}
return 0;
}

View file

@ -0,0 +1,70 @@
/*
* hostapd / Hardware feature query and different modes
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef HW_FEATURES_H
#define HW_FEATURES_H
#ifdef NEED_AP_MLME
void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features);
int hostapd_get_hw_features(struct hostapd_iface *iface);
int hostapd_select_hw_mode(struct hostapd_iface *iface);
const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode);
#else /* NEED_AP_MLME */
static inline void
hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
size_t num_hw_features)
{
}
static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
{
return -1;
}
static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
return -1;
}
static inline const char * hostapd_hw_mode_txt(int mode)
{
return NULL;
}
static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
{
return -1;
}
static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
{
return 0;
}
static inline int hostapd_prepare_rates(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode)
{
return 0;
}
#endif /* NEED_AP_MLME */
#endif /* HW_FEATURES_H */

535
hostapd-0.8/src/ap/iapp.c Normal file
View file

@ -0,0 +1,535 @@
/*
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
* and IEEE has withdrawn it. In other words, it is likely better to look at
* using some other mechanism for AP-to-AP communication than extending the
* implementation here.
*/
/* TODO:
* Level 1: no administrative or security support
* (e.g., static BSSID to IP address mapping in each AP)
* Level 2: support for dynamic mapping of BSSID to IP address
* Level 3: support for encryption and authentication of IAPP messages
* - add support for MOVE-notify and MOVE-response (this requires support for
* finding out IP address for previous AP using RADIUS)
* - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
* reassociation to another AP
* - implement counters etc. for IAPP MIB
* - verify endianness of fields in IAPP messages; are they big-endian as
* used here?
* - RADIUS connection for AP registration and BSSID to IP address mapping
* - TCP connection for IAPP MOVE, CACHE
* - broadcast ESP for IAPP ADD-notify
* - ESP for IAPP MOVE messages
* - security block sending/processing
* - IEEE 802.11 context transfer
*/
#include "utils/includes.h"
#include <net/if.h>
#include <sys/ioctl.h>
#ifdef USE_KERNEL_HEADERS
#include <linux/if_packet.h>
#else /* USE_KERNEL_HEADERS */
#include <netpacket/packet.h>
#endif /* USE_KERNEL_HEADERS */
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "iapp.h"
#define IAPP_MULTICAST "224.0.1.178"
#define IAPP_UDP_PORT 3517
#define IAPP_TCP_PORT 3517
struct iapp_hdr {
u8 version;
u8 command;
be16 identifier;
be16 length;
/* followed by length-6 octets of data */
} __attribute__ ((packed));
#define IAPP_VERSION 0
enum IAPP_COMMAND {
IAPP_CMD_ADD_notify = 0,
IAPP_CMD_MOVE_notify = 1,
IAPP_CMD_MOVE_response = 2,
IAPP_CMD_Send_Security_Block = 3,
IAPP_CMD_ACK_Security_Block = 4,
IAPP_CMD_CACHE_notify = 5,
IAPP_CMD_CACHE_response = 6,
};
/* ADD-notify - multicast UDP on the local LAN */
struct iapp_add_notify {
u8 addr_len; /* ETH_ALEN */
u8 reserved;
u8 mac_addr[ETH_ALEN];
be16 seq_num;
} __attribute__ ((packed));
/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
struct iapp_layer2_update {
u8 da[ETH_ALEN]; /* broadcast */
u8 sa[ETH_ALEN]; /* STA addr */
be16 len; /* 6 */
u8 dsap; /* null DSAP address */
u8 ssap; /* null SSAP address, CR=Response */
u8 control;
u8 xid_info[3];
} __attribute__ ((packed));
/* MOVE-notify - unicast TCP */
struct iapp_move_notify {
u8 addr_len; /* ETH_ALEN */
u8 reserved;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
u16 ctx_block_len;
/* followed by ctx_block_len bytes */
} __attribute__ ((packed));
/* MOVE-response - unicast TCP */
struct iapp_move_response {
u8 addr_len; /* ETH_ALEN */
u8 status;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
u16 ctx_block_len;
/* followed by ctx_block_len bytes */
} __attribute__ ((packed));
enum {
IAPP_MOVE_SUCCESSFUL = 0,
IAPP_MOVE_DENIED = 1,
IAPP_MOVE_STALE_MOVE = 2,
};
/* CACHE-notify */
struct iapp_cache_notify {
u8 addr_len; /* ETH_ALEN */
u8 reserved;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
u8 current_ap[ETH_ALEN];
u16 ctx_block_len;
/* ctx_block_len bytes of context block followed by 16-bit context
* timeout */
} __attribute__ ((packed));
/* CACHE-response - unicast TCP */
struct iapp_cache_response {
u8 addr_len; /* ETH_ALEN */
u8 status;
u8 mac_addr[ETH_ALEN];
u16 seq_num;
} __attribute__ ((packed));
enum {
IAPP_CACHE_SUCCESSFUL = 0,
IAPP_CACHE_STALE_CACHE = 1,
};
/* Send-Security-Block - unicast TCP */
struct iapp_send_security_block {
u8 iv[8];
u16 sec_block_len;
/* followed by sec_block_len bytes of security block */
} __attribute__ ((packed));
/* ACK-Security-Block - unicast TCP */
struct iapp_ack_security_block {
u8 iv[8];
u8 new_ap_ack_authenticator[48];
} __attribute__ ((packed));
struct iapp_data {
struct hostapd_data *hapd;
u16 identifier; /* next IAPP identifier */
struct in_addr own, multicast;
int udp_sock;
int packet_sock;
};
static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
{
char buf[128];
struct iapp_hdr *hdr;
struct iapp_add_notify *add;
struct sockaddr_in addr;
/* Send IAPP ADD-notify to remove possible association from other APs
*/
hdr = (struct iapp_hdr *) buf;
hdr->version = IAPP_VERSION;
hdr->command = IAPP_CMD_ADD_notify;
hdr->identifier = host_to_be16(iapp->identifier++);
hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
add = (struct iapp_add_notify *) (hdr + 1);
add->addr_len = ETH_ALEN;
add->reserved = 0;
os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
add->seq_num = host_to_be16(seq_num);
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = iapp->multicast.s_addr;
addr.sin_port = htons(IAPP_UDP_PORT);
if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
(struct sockaddr *) &addr, sizeof(addr)) < 0)
perror("sendto[IAPP-ADD]");
}
static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
{
struct iapp_layer2_update msg;
/* Send Level 2 Update Frame to update forwarding tables in layer 2
* bridge devices */
/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
* Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
os_memset(msg.da, 0xff, ETH_ALEN);
os_memcpy(msg.sa, addr, ETH_ALEN);
msg.len = host_to_be16(6);
msg.dsap = 0; /* NULL DSAP address */
msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
msg.control = 0xaf; /* XID response lsb.1111F101.
* F=0 (no poll command; unsolicited frame) */
msg.xid_info[0] = 0x81; /* XID format identifier */
msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
* FIX: what is correct RW with 802.11? */
if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
perror("send[L2 Update]");
}
/**
* iapp_new_station - IAPP processing for a new STA
* @iapp: IAPP data
* @sta: The associated station
*/
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
{
struct ieee80211_mgmt *assoc;
u16 seq;
if (iapp == NULL)
return;
assoc = sta->last_assoc_req;
seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
iapp_send_layer2_update(iapp, sta->addr);
iapp_send_add(iapp, sta->addr, seq);
if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
WLAN_FC_STYPE_REASSOC_REQ) {
/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
* Context Block, Timeout)
*/
/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
* IP address */
}
}
static void iapp_process_add_notify(struct iapp_data *iapp,
struct sockaddr_in *from,
struct iapp_hdr *hdr, int len)
{
struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
struct sta_info *sta;
if (len != sizeof(*add)) {
printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
len, (unsigned long) sizeof(*add));
return;
}
sta = ap_get_sta(iapp->hapd, add->mac_addr);
/* IAPP-ADD.indication(MAC Address, Sequence Number) */
hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_INFO,
"Received IAPP ADD-notify (seq# %d) from %s:%d%s",
be_to_host16(add->seq_num),
inet_ntoa(from->sin_addr), ntohs(from->sin_port),
sta ? "" : " (STA not found)");
if (!sta)
return;
/* TODO: could use seq_num to try to determine whether last association
* to this AP is newer than the one advertised in IAPP-ADD. Although,
* this is not really a reliable verification. */
hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG,
"Removing STA due to IAPP ADD-notify");
ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
}
/**
* iapp_receive_udp - Process IAPP UDP frames
* @sock: File descriptor for the socket
* @eloop_ctx: IAPP data (struct iapp_data *)
* @sock_ctx: Not used
*/
static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
{
struct iapp_data *iapp = eloop_ctx;
int len, hlen;
unsigned char buf[128];
struct sockaddr_in from;
socklen_t fromlen;
struct iapp_hdr *hdr;
/* Handle incoming IAPP frames (over UDP/IP) */
fromlen = sizeof(from);
len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
(struct sockaddr *) &from, &fromlen);
if (len < 0) {
perror("recvfrom");
return;
}
if (from.sin_addr.s_addr == iapp->own.s_addr)
return; /* ignore own IAPP messages */
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG,
"Received %d byte IAPP frame from %s%s\n",
len, inet_ntoa(from.sin_addr),
len < (int) sizeof(*hdr) ? " (too short)" : "");
if (len < (int) sizeof(*hdr))
return;
hdr = (struct iapp_hdr *) buf;
hlen = be_to_host16(hdr->length);
hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
HOSTAPD_LEVEL_DEBUG,
"RX: version=%d command=%d id=%d len=%d\n",
hdr->version, hdr->command,
be_to_host16(hdr->identifier), hlen);
if (hdr->version != IAPP_VERSION) {
printf("Dropping IAPP frame with unknown version %d\n",
hdr->version);
return;
}
if (hlen > len) {
printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
return;
}
if (hlen < len) {
printf("Ignoring %d extra bytes from IAPP frame\n",
len - hlen);
len = hlen;
}
switch (hdr->command) {
case IAPP_CMD_ADD_notify:
iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
break;
case IAPP_CMD_MOVE_notify:
/* TODO: MOVE is using TCP; so move this to TCP handler once it
* is implemented.. */
/* IAPP-MOVE.indication(MAC Address, New BSSID,
* Sequence Number, AP Address, Context Block) */
/* TODO: process */
break;
default:
printf("Unknown IAPP command %d\n", hdr->command);
break;
}
}
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
{
struct ifreq ifr;
struct sockaddr_ll addr;
int ifindex;
struct sockaddr_in *paddr, uaddr;
struct iapp_data *iapp;
struct ip_mreqn mreq;
iapp = os_zalloc(sizeof(*iapp));
if (iapp == NULL)
return NULL;
iapp->hapd = hapd;
iapp->udp_sock = iapp->packet_sock = -1;
/* TODO:
* open socket for sending and receiving IAPP frames over TCP
*/
iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (iapp->udp_sock < 0) {
perror("socket[PF_INET,SOCK_DGRAM]");
iapp_deinit(iapp);
return NULL;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
perror("ioctl(SIOCGIFINDEX)");
iapp_deinit(iapp);
return NULL;
}
ifindex = ifr.ifr_ifindex;
if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFADDR)");
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
printf("Invalid address family %i (SIOCGIFADDR)\n",
paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
iapp->own.s_addr = paddr->sin_addr.s_addr;
if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
perror("ioctl(SIOCGIFBRDADDR)");
iapp_deinit(iapp);
return NULL;
}
paddr = (struct sockaddr_in *) &ifr.ifr_addr;
if (paddr->sin_family != AF_INET) {
printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
paddr->sin_family);
iapp_deinit(iapp);
return NULL;
}
inet_aton(IAPP_MULTICAST, &iapp->multicast);
os_memset(&uaddr, 0, sizeof(uaddr));
uaddr.sin_family = AF_INET;
uaddr.sin_port = htons(IAPP_UDP_PORT);
if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
sizeof(uaddr)) < 0) {
perror("bind[UDP]");
iapp_deinit(iapp);
return NULL;
}
os_memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr = iapp->multicast;
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
sizeof(mreq)) < 0) {
perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
iapp_deinit(iapp);
return NULL;
}
iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (iapp->packet_sock < 0) {
perror("socket[PF_PACKET,SOCK_RAW]");
iapp_deinit(iapp);
return NULL;
}
os_memset(&addr, 0, sizeof(addr));
addr.sll_family = AF_PACKET;
addr.sll_ifindex = ifindex;
if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
sizeof(addr)) < 0) {
perror("bind[PACKET]");
iapp_deinit(iapp);
return NULL;
}
if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
iapp, NULL)) {
printf("Could not register read socket for IAPP.\n");
iapp_deinit(iapp);
return NULL;
}
printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
* RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
* be openned only after receiving Initiate-Accept. If Initiate-Reject
* is received, IAPP is not started. */
return iapp;
}
void iapp_deinit(struct iapp_data *iapp)
{
struct ip_mreqn mreq;
if (iapp == NULL)
return;
if (iapp->udp_sock >= 0) {
os_memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr = iapp->multicast;
mreq.imr_address.s_addr = INADDR_ANY;
mreq.imr_ifindex = 0;
if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
&mreq, sizeof(mreq)) < 0) {
perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
}
eloop_unregister_read_sock(iapp->udp_sock);
close(iapp->udp_sock);
}
if (iapp->packet_sock >= 0) {
eloop_unregister_read_sock(iapp->packet_sock);
close(iapp->packet_sock);
}
os_free(iapp);
}

45
hostapd-0.8/src/ap/iapp.h Normal file
View file

@ -0,0 +1,45 @@
/*
* hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
* Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IAPP_H
#define IAPP_H
struct iapp_data;
#ifdef CONFIG_IAPP
void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
void iapp_deinit(struct iapp_data *iapp);
#else /* CONFIG_IAPP */
static inline void iapp_new_station(struct iapp_data *iapp,
struct sta_info *sta)
{
}
static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
const char *iface)
{
return NULL;
}
static inline void iapp_deinit(struct iapp_data *iapp)
{
}
#endif /* CONFIG_IAPP */
#endif /* IAPP_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,68 @@
/*
* hostapd / IEEE 802.11 Management
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_11_H
#define IEEE802_11_H
struct hostapd_iface;
struct hostapd_data;
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
u16 stype, int ok);
void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
#ifdef NEED_AP_MLME
int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
#else /* NEED_AP_MLME */
static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf,
size_t buflen)
{
return 0;
}
static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
return 0;
}
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
int hostapd_ht_operation_update(struct hostapd_iface *iface);
void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
const u8 *addr, const u8 *trans_id);
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
int wds);
#endif /* IEEE802_11_H */

View file

@ -0,0 +1,524 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* Access control list for IEEE 802.11 authentication can uses statically
* configured ACL from configuration files or an external RADIUS server.
* Results from external RADIUS queries are cached to allow faster
* authentication frame processing.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_11.h"
#include "ieee802_11_auth.h"
#define RADIUS_ACL_TIMEOUT 30
struct hostapd_cached_radius_acl {
os_time_t timestamp;
macaddr addr;
int accepted; /* HOSTAPD_ACL_* */
struct hostapd_cached_radius_acl *next;
u32 session_timeout;
u32 acct_interim_interval;
int vlan_id;
};
struct hostapd_acl_query_data {
os_time_t timestamp;
u8 radius_id;
macaddr addr;
u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
size_t auth_msg_len;
struct hostapd_acl_query_data *next;
};
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
{
struct hostapd_cached_radius_acl *prev;
while (acl_cache) {
prev = acl_cache;
acl_cache = acl_cache->next;
os_free(prev);
}
}
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
os_get_time(&now);
entry = hapd->acl_cache;
while (entry) {
if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
return -1; /* entry has expired */
if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
if (session_timeout)
*session_timeout =
entry->session_timeout;
if (acct_interim_interval)
*acct_interim_interval =
entry->acct_interim_interval;
if (vlan_id)
*vlan_id = entry->vlan_id;
return entry->accepted;
}
entry = entry->next;
}
return -1;
}
#endif /* CONFIG_NO_RADIUS */
static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
{
if (query == NULL)
return;
os_free(query->auth_msg);
os_free(query);
}
#ifndef CONFIG_NO_RADIUS
static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
struct hostapd_acl_query_data *query)
{
struct radius_msg *msg;
char buf[128];
query->radius_id = radius_client_get_id(hapd->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
if (msg == NULL)
return -1;
radius_msg_make_authenticator(msg, addr, ETH_ALEN);
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add User-Name");
goto fail;
}
if (!radius_msg_add_attr_user_password(
msg, (u8 *) buf, os_strlen(buf),
hapd->conf->radius->auth_server->shared_secret,
hapd->conf->radius->auth_server->shared_secret_len)) {
wpa_printf(MSG_DEBUG, "Could not add User-Password");
goto fail;
}
if (hapd->conf->own_ip_addr.af == AF_INET &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
goto fail;
}
#ifdef CONFIG_IPV6
if (hapd->conf->own_ip_addr.af == AF_INET6 &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
(u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
goto fail;
}
#endif /* CONFIG_IPV6 */
if (hapd->conf->nas_identifier &&
!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
(u8 *) hapd->conf->nas_identifier,
os_strlen(hapd->conf->nas_identifier))) {
wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
goto fail;
}
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
goto fail;
}
if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
goto fail;
}
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
goto fail;
}
radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
return 0;
fail:
radius_msg_free(msg);
return -1;
}
#endif /* CONFIG_NO_RADIUS */
/**
* hostapd_allowed_address - Check whether a specified STA can be authenticated
* @hapd: hostapd BSS data
* @addr: MAC address of the STA
* @msg: Authentication message
* @len: Length of msg in octets
* @session_timeout: Buffer for returning session timeout (from RADIUS)
* @acct_interim_interval: Buffer for returning account interval (from RADIUS)
* @vlan_id: Buffer for returning VLAN ID
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id)
{
if (session_timeout)
*session_timeout = 0;
if (acct_interim_interval)
*acct_interim_interval = 0;
if (vlan_id)
*vlan_id = 0;
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
return HOSTAPD_ACL_ACCEPT;
if (hostapd_maclist_found(hapd->conf->deny_mac,
hapd->conf->num_deny_mac, addr, vlan_id))
return HOSTAPD_ACL_REJECT;
if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
return HOSTAPD_ACL_ACCEPT;
if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
return HOSTAPD_ACL_REJECT;
if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
#ifdef CONFIG_NO_RADIUS
return HOSTAPD_ACL_REJECT;
#else /* CONFIG_NO_RADIUS */
struct hostapd_acl_query_data *query;
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
vlan_id);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
if (res == HOSTAPD_ACL_REJECT)
return HOSTAPD_ACL_REJECT;
query = hapd->acl_queries;
while (query) {
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
return HOSTAPD_ACL_PENDING;
}
query = query->next;
}
if (!hapd->conf->radius->auth_server)
return HOSTAPD_ACL_REJECT;
/* No entry in the cache - query external RADIUS server */
query = os_zalloc(sizeof(*query));
if (query == NULL) {
wpa_printf(MSG_ERROR, "malloc for query data failed");
return HOSTAPD_ACL_REJECT;
}
time(&query->timestamp);
os_memcpy(query->addr, addr, ETH_ALEN);
if (hostapd_radius_acl_query(hapd, addr, query)) {
wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
"for ACL query.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
query->auth_msg = os_malloc(len);
if (query->auth_msg == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"auth frame.");
hostapd_acl_query_free(query);
return HOSTAPD_ACL_REJECT;
}
os_memcpy(query->auth_msg, msg, len);
query->auth_msg_len = len;
query->next = hapd->acl_queries;
hapd->acl_queries = query;
/* Queued data will be processed in hostapd_acl_recv_radius()
* when RADIUS server replies to the sent Access-Request. */
return HOSTAPD_ACL_PENDING;
#endif /* CONFIG_NO_RADIUS */
}
return HOSTAPD_ACL_REJECT;
}
#ifndef CONFIG_NO_RADIUS
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
{
struct hostapd_cached_radius_acl *prev, *entry, *tmp;
prev = NULL;
entry = hapd->acl_cache;
while (entry) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
prev->next = entry->next;
else
hapd->acl_cache = entry->next;
hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
tmp = entry;
entry = entry->next;
os_free(tmp);
continue;
}
prev = entry;
entry = entry->next;
}
}
static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
os_time_t now)
{
struct hostapd_acl_query_data *prev, *entry, *tmp;
prev = NULL;
entry = hapd->acl_queries;
while (entry) {
if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
" has expired.", MAC2STR(entry->addr));
if (prev)
prev->next = entry->next;
else
hapd->acl_queries = entry->next;
tmp = entry;
entry = entry->next;
hostapd_acl_query_free(tmp);
continue;
}
prev = entry;
entry = entry->next;
}
}
/**
* hostapd_acl_expire - ACL cache expiration callback
* @eloop_ctx: struct hostapd_data *
* @timeout_ctx: Not used
*/
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct os_time now;
os_get_time(&now);
hostapd_acl_expire_cache(hapd, now.sec);
hostapd_acl_expire_queries(hapd, now.sec);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
/**
* hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
* @msg: RADIUS response message
* @req: RADIUS request message
* @shared_secret: RADIUS shared secret
* @shared_secret_len: Length of shared_secret in octets
* @data: Context data (struct hostapd_data *)
* Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
* was processed here) or RADIUS_RX_UNKNOWN if not.
*/
static RadiusRxResult
hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
const u8 *shared_secret, size_t shared_secret_len,
void *data)
{
struct hostapd_data *hapd = data;
struct hostapd_acl_query_data *query, *prev;
struct hostapd_cached_radius_acl *cache;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
query = hapd->acl_queries;
prev = NULL;
while (query) {
if (query->radius_id == hdr->identifier)
break;
prev = query;
query = query->next;
}
if (query == NULL)
return RADIUS_RX_UNKNOWN;
wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
"message (id=%d)", query->radius_id);
if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
"correct authenticator - dropped\n");
return RADIUS_RX_INVALID_AUTHENTICATOR;
}
if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
hdr->code != RADIUS_CODE_ACCESS_REJECT) {
wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
"query", hdr->code);
return RADIUS_RX_UNKNOWN;
}
/* Insert Accept/Reject info into ACL cache */
cache = os_zalloc(sizeof(*cache));
if (cache == NULL) {
wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
goto done;
}
time(&cache->timestamp);
os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
else
cache->accepted = HOSTAPD_ACL_ACCEPT;
if (radius_msg_get_attr_int32(
msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
&cache->acct_interim_interval) == 0 &&
cache->acct_interim_interval < 60) {
wpa_printf(MSG_DEBUG, "Ignored too small "
"Acct-Interim-Interval %d for STA " MACSTR,
cache->acct_interim_interval,
MAC2STR(query->addr));
cache->acct_interim_interval = 0;
}
cache->vlan_id = radius_msg_get_vlanid(msg);
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
hapd->acl_cache = cache;
#ifdef CONFIG_DRIVER_RADIUS_ACL
hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
cache->session_timeout);
#else /* CONFIG_DRIVER_RADIUS_ACL */
#ifdef NEED_AP_MLME
/* Re-send original authentication frame for 802.11 processing */
wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
"successful RADIUS ACL query");
ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
#endif /* NEED_AP_MLME */
#endif /* CONFIG_DRIVER_RADIUS_ACL */
done:
if (prev == NULL)
hapd->acl_queries = query->next;
else
prev->next = query->next;
hostapd_acl_query_free(query);
return RADIUS_RX_PROCESSED;
}
#endif /* CONFIG_NO_RADIUS */
/**
* hostapd_acl_init: Initialize IEEE 802.11 ACL
* @hapd: hostapd BSS data
* Returns: 0 on success, -1 on failure
*/
int hostapd_acl_init(struct hostapd_data *hapd)
{
#ifndef CONFIG_NO_RADIUS
if (radius_client_register(hapd->radius, RADIUS_AUTH,
hostapd_acl_recv_radius, hapd))
return -1;
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
#endif /* CONFIG_NO_RADIUS */
return 0;
}
/**
* hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
* @hapd: hostapd BSS data
*/
void hostapd_acl_deinit(struct hostapd_data *hapd)
{
struct hostapd_acl_query_data *query, *prev;
#ifndef CONFIG_NO_RADIUS
eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
hostapd_acl_cache_free(hapd->acl_cache);
#endif /* CONFIG_NO_RADIUS */
query = hapd->acl_queries;
while (query) {
prev = query;
query = query->next;
hostapd_acl_query_free(prev);
}
}

View file

@ -0,0 +1,31 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_11_AUTH_H
#define IEEE802_11_AUTH_H
enum {
HOSTAPD_ACL_REJECT = 0,
HOSTAPD_ACL_ACCEPT = 1,
HOSTAPD_ACL_PENDING = 2,
HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
};
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
#endif /* IEEE802_11_AUTH_H */

View file

@ -0,0 +1,267 @@
/*
* hostapd / IEEE 802.11n HT
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008, Intel Corporation
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ap_config.h"
#include "sta_info.h"
#include "beacon.h"
#include "ieee802_11.h"
u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_ht_capabilities *cap;
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
hapd->conf->disable_11n)
return eid;
*pos++ = WLAN_EID_HT_CAP;
*pos++ = sizeof(*cap);
cap = (struct ieee80211_ht_capabilities *) pos;
os_memset(cap, 0, sizeof(*cap));
cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab);
cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params;
os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set,
16);
/* TODO: ht_extended_capabilities (now fully disabled) */
/* TODO: tx_bf_capability_info (now fully disabled) */
/* TODO: asel_capabilities (now fully disabled) */
pos += sizeof(*cap);
return pos;
}
u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
*pos++ = sizeof(*oper);
oper = (struct ieee80211_ht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
oper->control_chan = hapd->iconf->channel;
oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
if (hapd->iconf->secondary_channel == 1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
if (hapd->iconf->secondary_channel == -1)
oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
pos += sizeof(*oper);
return pos;
}
/*
op_mode
Set to 0 (HT pure) under the followign conditions
- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
Set to 1 (HT non-member protection) if there may be non-HT STAs
in both the primary and the secondary channel
Set to 2 if only HT STAs are associated in BSS,
however and at least one 20 MHz HT STA is associated
Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
*/
int hostapd_ht_operation_update(struct hostapd_iface *iface)
{
u16 cur_op_mode, new_op_mode;
int op_mode_changes = 0;
if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
return 0;
wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
__func__, iface->ht_op_mode);
if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
&& iface->num_sta_ht_no_gf) {
iface->ht_op_mode |=
HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
op_mode_changes++;
} else if ((iface->ht_op_mode &
HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
iface->num_sta_ht_no_gf == 0) {
iface->ht_op_mode &=
~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
op_mode_changes++;
}
if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
(iface->num_sta_no_ht || iface->olbc_ht)) {
iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
op_mode_changes++;
} else if ((iface->ht_op_mode &
HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
(iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
iface->ht_op_mode &=
~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
op_mode_changes++;
}
new_op_mode = 0;
if (iface->num_sta_no_ht)
new_op_mode = OP_MODE_MIXED;
else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
&& iface->num_sta_ht_20mhz)
new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
else if (iface->olbc_ht)
new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
else
new_op_mode = OP_MODE_PURE;
cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
if (cur_op_mode != new_op_mode) {
iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
iface->ht_op_mode |= new_op_mode;
op_mode_changes++;
}
wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
__func__, iface->ht_op_mode, op_mode_changes);
return op_mode_changes;
}
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
{
/* Disable HT caps for STAs associated to no-HT BSSes. */
if (!ht_capab ||
ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
return WLAN_STATUS_SUCCESS;
}
if (sta->ht_capabilities == NULL) {
sta->ht_capabilities =
os_zalloc(sizeof(struct ieee80211_ht_capabilities));
if (sta->ht_capabilities == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
sta->flags |= WLAN_STA_HT;
os_memcpy(sta->ht_capabilities, ht_capab,
sizeof(struct ieee80211_ht_capabilities));
return WLAN_STATUS_SUCCESS;
}
static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
{
u16 ht_capab;
ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info);
wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: "
"0x%04x", MAC2STR(sta->addr), ht_capab);
if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
if (!sta->no_ht_gf_set) {
sta->no_ht_gf_set = 1;
hapd->iface->num_sta_ht_no_gf++;
}
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num "
"of non-gf stations %d",
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_no_gf);
}
if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
if (!sta->ht_20mhz_set) {
sta->ht_20mhz_set = 1;
hapd->iface->num_sta_ht_20mhz++;
}
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of "
"20MHz HT STAs %d",
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_ht_20mhz);
}
}
static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
{
if (!sta->no_ht_set) {
sta->no_ht_set = 1;
hapd->iface->num_sta_no_ht++;
}
if (hapd->iconf->ieee80211n) {
wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of "
"non-HT stations %d",
__func__, MAC2STR(sta->addr),
hapd->iface->num_sta_no_ht);
}
}
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
{
if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
update_sta_ht(hapd, sta);
else
update_sta_no_ht(hapd, sta);
if (hostapd_ht_operation_update(hapd->iface) > 0)
ieee802_11_set_beacons(hapd->iface);
}
void hostapd_get_ht_capab(struct hostapd_data *hapd,
struct ieee80211_ht_capabilities *ht_cap,
struct ieee80211_ht_capabilities *neg_ht_cap)
{
u16 cap;
if (ht_cap == NULL)
return;
os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
cap &= hapd->iconf->ht_capab;
cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
/*
* STBC needs to be handled specially
* if we don't support RX STBC, mask out TX STBC in the STA's HT caps
* if we don't support TX STBC, mask out RX STBC in the STA's HT caps
*/
if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK))
cap &= ~HT_CAP_INFO_TX_STBC;
if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC))
cap &= ~HT_CAP_INFO_RX_STBC_MASK;
neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,89 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_1X_H
#define IEEE802_1X_H
struct hostapd_data;
struct sta_info;
struct eapol_state_machine;
struct hostapd_config;
struct hostapd_bss_config;
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
/* RFC 3580, 4. RC4 EAPOL-Key Frame */
struct ieee802_1x_eapol_key {
u8 type;
u16 key_length;
u8 replay_counter[8]; /* does not repeat within the life of the keying
* material used to encrypt the Key field;
* 64-bit NTP timestamp MAY be used here */
u8 key_iv[16]; /* cryptographically random number */
u8 key_index; /* key flag in the most significant bit:
* 0 = broadcast (default key),
* 1 = unicast (key mapping key); key index is in the
* 7 least significant bits */
u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
* MS-MPPE-Send-Key as the key */
/* followed by key: if packet body length = 44 + key length, then the
* key field (of key_length bytes) contains the key in encrypted form;
* if packet body length = 44, key field is absent and key_length
* represents the number of least significant octets from
* MS-MPPE-Send-Key attribute to be used as the keying material;
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
size_t len);
void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_free_station(struct sta_info *sta);
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
int ieee802_1x_init(struct hostapd_data *hapd);
void ieee802_1x_deinit(struct hostapd_data *hapd);
int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *buf, size_t len, int ack);
u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
int idx);
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
int enabled);
void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
int valid);
void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
void hostapd_get_ntp_timestamp(u8 *buf);
char *eap_type_text(u8 type);
const char *radius_mode_txt(struct hostapd_data *hapd);
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
#endif /* IEEE802_1X_H */

View file

@ -0,0 +1,120 @@
/*
* hostapd / P2P integration
* Copyright (c) 2009-2010, Atheros Communications
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "sta_info.h"
#include "p2p_hostapd.h"
#ifdef CONFIG_P2P
int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen)
{
if (sta->p2p_ie == NULL)
return 0;
return p2p_ie_text(sta->p2p_ie, buf, buf + buflen);
}
int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration)
{
wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d "
"duration=%d", count, start, duration);
if (count == 0) {
hapd->noa_enabled = 0;
hapd->noa_start = 0;
hapd->noa_duration = 0;
}
if (count != 255) {
wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set "
"NoA parameters");
return hostapd_driver_set_noa(hapd, count, start, duration);
}
hapd->noa_enabled = 1;
hapd->noa_start = start;
hapd->noa_duration = duration;
if (hapd->num_sta_no_p2p == 0) {
wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update "
"periodic NoA parameters");
return hostapd_driver_set_noa(hapd, count, start, duration);
}
wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable "
"periodic NoA");
return 0;
}
void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected");
if (hapd->noa_enabled) {
wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA");
hostapd_driver_set_noa(hapd, 0, 0, 0);
}
}
void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd)
{
wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected");
if (hapd->noa_enabled) {
wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA");
hostapd_driver_set_noa(hapd, 255, hapd->noa_start,
hapd->noa_duration);
}
}
#endif /* CONFIG_P2P */
#ifdef CONFIG_P2P_MANAGER
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
{
u8 bitmap;
*eid++ = WLAN_EID_VENDOR_SPECIFIC;
*eid++ = 4 + 3 + 1;
WPA_PUT_BE24(eid, OUI_WFA);
eid += 3;
*eid++ = P2P_OUI_TYPE;
*eid++ = P2P_ATTR_MANAGEABILITY;
WPA_PUT_LE16(eid, 1);
eid += 2;
bitmap = P2P_MAN_DEVICE_MANAGEMENT;
if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION)
bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED;
bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL;
*eid++ = bitmap;
return eid;
}
#endif /* CONFIG_P2P_MANAGER */

View file

@ -0,0 +1,41 @@
/*
* hostapd / P2P integration
* Copyright (c) 2009-2010, Atheros Communications
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef P2P_HOSTAPD_H
#define P2P_HOSTAPD_H
#ifdef CONFIG_P2P
int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
char *buf, size_t buflen);
int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
int duration);
void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd);
void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd);
#else /* CONFIG_P2P */
static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
return 0;
}
#endif /* CONFIG_P2P */
u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid);
#endif /* P2P_HOSTAPD_H */

View file

@ -0,0 +1,402 @@
/*
* hostapd - PeerKey for Direct Link Setup (DLS)
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/random.h"
#include "wpa_auth.h"
#include "wpa_auth_i.h"
#include "wpa_auth_ie.h"
#ifdef CONFIG_PEERKEY
static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
{
#if 0
struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_stsl_negotiation *neg = timeout_ctx;
#endif
/* TODO: ? */
}
struct wpa_stsl_search {
const u8 *addr;
struct wpa_state_machine *sm;
};
static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
{
struct wpa_stsl_search *search = ctx;
if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
search->sm = sm;
return 1;
}
return 0;
}
static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, const u8 *peer,
u16 mui, u16 error_type)
{
u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
u8 *pos;
struct rsn_error_kde error;
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"Sending SMK Error");
pos = kde;
if (peer) {
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
NULL, 0);
}
error.mui = host_to_be16(mui);
error.error_type = host_to_be16(error_type);
pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
(u8 *) &error, sizeof(error), NULL, 0);
__wpa_send_eapol(wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
NULL, NULL, kde, pos - kde, 0, 0, 0);
}
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 *buf, *pos;
size_t buf_len;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
return;
}
if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
kde.mac_addr_len < ETH_ALEN) {
wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
"SMK M1");
return;
}
/* Initiator = sm->addr; Peer = kde.mac_addr */
search.addr = kde.mac_addr;
search.sm = NULL;
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
0 || search.sm == NULL) {
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
" aborted - STA not associated anymore",
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
buf = os_malloc(buf_len);
if (buf == NULL)
return;
/* Initiator RSN IE */
os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
pos = buf + kde.rsn_ie_len;
/* Initiator MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
NULL, 0);
/* SMK M2:
* EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
* MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
*/
wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
"Sending SMK M2");
__wpa_send_eapol(wpa_auth, search.sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
os_free(buf);
}
static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
struct wpa_eapol_key *key,
struct wpa_eapol_ie_parse *kde,
const u8 *smk)
{
u8 *buf, *pos;
size_t buf_len;
u32 lifetime;
/* SMK M4:
* EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
* MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
* Lifetime KDE)
*/
buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
pos = buf = os_malloc(buf_len);
if (buf == NULL)
return;
/* Initiator MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
NULL, 0);
/* Initiator Nonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
NULL, 0);
/* SMK with PNonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
key->key_nonce, WPA_NONCE_LEN);
/* Lifetime */
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Sending SMK M4");
__wpa_send_eapol(wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
os_free(buf);
}
static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
struct wpa_eapol_key *key,
struct wpa_eapol_ie_parse *kde,
const u8 *smk, const u8 *peer)
{
u8 *buf, *pos;
size_t buf_len;
u32 lifetime;
/* SMK M5:
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
* MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
* Lifetime KDE))
*/
buf_len = kde->rsn_ie_len +
2 + RSN_SELECTOR_LEN + ETH_ALEN +
2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
2 + RSN_SELECTOR_LEN + sizeof(lifetime);
pos = buf = os_malloc(buf_len);
if (buf == NULL)
return;
/* Peer RSN IE */
os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
pos = buf + kde->rsn_ie_len;
/* Peer MAC Address */
pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
/* PNonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
WPA_NONCE_LEN, NULL, 0);
/* SMK and INonce */
pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
kde->nonce, WPA_NONCE_LEN);
/* Lifetime */
lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
(u8 *) &lifetime, sizeof(lifetime), NULL, 0);
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Sending SMK M5");
__wpa_send_eapol(wpa_auth, sm,
WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
WPA_KEY_INFO_SMK_MESSAGE,
NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
os_free(buf);
}
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
return;
}
if (kde.rsn_ie == NULL ||
kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
"Nonce KDE in SMK M3");
return;
}
/* Peer = sm->addr; Initiator = kde.mac_addr;
* Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
search.addr = kde.mac_addr;
search.sm = NULL;
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
0 || search.sm == NULL) {
wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
" aborted - STA not associated anymore",
MAC2STR(kde.mac_addr));
wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
STK_ERR_STA_NR);
/* FIX: wpa_stsl_remove(wpa_auth, neg); */
return;
}
if (random_get_bytes(smk, PMK_LEN)) {
wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
return;
}
/* SMK = PRF-256(Random number, "SMK Derivation",
* AA || Time || INonce || PNonce)
*/
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
pos = buf + ETH_ALEN;
wpa_get_ntp_timestamp(pos);
pos += 8;
os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
#ifdef CONFIG_IEEE80211W
sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
smk, PMK_LEN);
#else /* CONFIG_IEEE80211W */
sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
smk, PMK_LEN);
#endif /* CONFIG_IEEE80211W */
wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
/* Authenticator does not need SMK anymore and it is required to forget
* it. */
os_memset(smk, 0, sizeof(*smk));
}
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key)
{
struct wpa_eapol_ie_parse kde;
struct wpa_stsl_search search;
struct rsn_error_kde error;
u16 mui, error_type;
if (wpa_parse_kde_ies((const u8 *) (key + 1),
WPA_GET_BE16(key->key_data_length), &kde) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
return;
}
if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
kde.error == NULL || kde.error_len < sizeof(error)) {
wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
"SMK Error");
return;
}
search.addr = kde.mac_addr;
search.sm = NULL;
if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
0 || search.sm == NULL) {
wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
"associated for SMK Error message from " MACSTR,
MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
return;
}
os_memcpy(&error, kde.error, sizeof(error));
mui = be_to_host16(error.mui);
error_type = be_to_host16(error.error_type);
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"STA reported SMK Error: Peer " MACSTR
" MUI %d Error Type %d",
MAC2STR(kde.mac_addr), mui, error_type);
wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
}
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg)
{
struct wpa_stsl_negotiation *pos, *prev;
if (wpa_auth == NULL)
return -1;
pos = wpa_auth->stsl_negotiations;
prev = NULL;
while (pos) {
if (pos == neg) {
if (prev)
prev->next = pos->next;
else
wpa_auth->stsl_negotiations = pos->next;
eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
os_free(pos);
return 0;
}
prev = pos;
pos = pos->next;
}
return -1;
}
#endif /* CONFIG_PEERKEY */

View file

@ -0,0 +1,425 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "sta_info.h"
#include "ap_config.h"
#include "pmksa_cache_auth.h"
static const int pmksa_cache_max_entries = 1024;
static const int dot11RSNAConfigPMKLifetime = 43200;
struct rsn_pmksa_cache {
#define PMKID_HASH_SIZE 128
#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
struct rsn_pmksa_cache_entry *pmksa;
int pmksa_count;
void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
void *ctx;
};
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
if (entry == NULL)
return;
os_free(entry->identity);
#ifndef CONFIG_NO_RADIUS
radius_free_class(&entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
os_free(entry);
}
static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
pmksa->pmksa_count--;
pmksa->free_cb(entry, pmksa->ctx);
pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL) {
prev->hnext = pos->hnext;
} else {
pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
pos->hnext;
}
break;
}
prev = pos;
pos = pos->hnext;
}
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos == entry) {
if (prev != NULL)
prev->next = pos->next;
else
pmksa->pmksa = pos->next;
break;
}
prev = pos;
pos = pos->next;
}
_pmksa_cache_free_entry(entry);
}
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
struct os_time now;
os_get_time(&now);
while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
pmksa->pmksa = entry->next;
wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
MACSTR, MAC2STR(entry->spa));
pmksa_cache_free_entry(pmksa, entry);
}
pmksa_cache_set_expiration(pmksa);
}
static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
{
int sec;
struct os_time now;
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
if (pmksa->pmksa == NULL)
return;
os_get_time(&now);
sec = pmksa->pmksa->expiration - now.sec;
if (sec < 0)
sec = 0;
eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
}
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (eapol == NULL)
return;
if (eapol->identity) {
entry->identity = os_malloc(eapol->identity_len);
if (entry->identity) {
entry->identity_len = eapol->identity_len;
os_memcpy(entry->identity, eapol->identity,
eapol->identity_len);
}
}
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &eapol->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
}
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (entry == NULL || eapol == NULL)
return;
if (entry->identity) {
os_free(eapol->identity);
eapol->identity = os_malloc(entry->identity_len);
if (eapol->identity) {
eapol->identity_len = entry->identity_len;
os_memcpy(eapol->identity, entry->identity,
entry->identity_len);
}
wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
eapol->identity, eapol->identity_len);
}
#ifndef CONFIG_NO_RADIUS
radius_free_class(&eapol->radius_class);
radius_copy_class(&eapol->radius_class, &entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
if (eapol->radius_class.attr) {
wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
"PMKSA", (unsigned long) eapol->radius_class.count);
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
}
static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry)
{
struct rsn_pmksa_cache_entry *pos, *prev;
/* Add the new entry; order by expiration time */
pos = pmksa->pmksa;
prev = NULL;
while (pos) {
if (pos->expiration > entry->expiration)
break;
prev = pos;
pos = pos->next;
}
if (prev == NULL) {
entry->next = pmksa->pmksa;
pmksa->pmksa = entry;
} else {
entry->next = prev->next;
prev->next = entry;
}
entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
pmksa->pmksa_count++;
wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
MAC2STR(entry->spa));
wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
}
/**
* pmksa_cache_auth_add - Add a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
* @aa: Authenticator address
* @spa: Supplicant address
* @session_timeout: Session timeout
* @eapol: Pointer to EAPOL state machine data
* @akmp: WPA_KEY_MGMT_* used in key derivation
* Returns: Pointer to the added PMKSA cache entry or %NULL on error
*
* This function create a PMKSA entry for a new PMK and adds it to the PMKSA
* cache. If an old entry is already in the cache for the same Supplicant,
* this entry will be replaced with the new entry. PMKID will be calculated
* based on the PMK.
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos;
struct os_time now;
if (pmk_len > PMK_LEN)
return NULL;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
os_get_time(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
entry->expiration += session_timeout;
else
entry->expiration += dot11RSNAConfigPMKLifetime;
entry->akmp = akmp;
os_memcpy(entry->spa, spa, ETH_ALEN);
pmksa_cache_from_eapol_data(entry, eapol);
/* Replace an old entry for the same STA (if found) with the new entry
*/
pos = pmksa_cache_auth_get(pmksa, spa, NULL);
if (pos)
pmksa_cache_free_entry(pmksa, pos);
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
/* Remove the oldest entry to make room for the new entry */
wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
"entry (for " MACSTR ") to make room for new one",
MAC2STR(pmksa->pmksa->spa));
pmksa_cache_free_entry(pmksa, pmksa->pmksa);
}
pmksa_cache_link_entry(pmksa, entry);
return entry;
}
struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid)
{
struct rsn_pmksa_cache_entry *entry;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
entry->pmk_len = old_entry->pmk_len;
entry->expiration = old_entry->expiration;
entry->akmp = old_entry->akmp;
os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
entry->opportunistic = 1;
if (old_entry->identity) {
entry->identity = os_malloc(old_entry->identity_len);
if (entry->identity) {
entry->identity_len = old_entry->identity_len;
os_memcpy(entry->identity, old_entry->identity,
old_entry->identity_len);
}
}
#ifndef CONFIG_NO_RADIUS
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = old_entry->eap_type_authsrv;
entry->vlan_id = old_entry->vlan_id;
entry->opportunistic = 1;
pmksa_cache_link_entry(pmksa, entry);
return entry;
}
/**
* pmksa_cache_auth_deinit - Free all entries in PMKSA cache
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
*/
void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
{
struct rsn_pmksa_cache_entry *entry, *prev;
int i;
if (pmksa == NULL)
return;
entry = pmksa->pmksa;
while (entry) {
prev = entry;
entry = entry->next;
_pmksa_cache_free_entry(prev);
}
eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
for (i = 0; i < PMKID_HASH_SIZE; i++)
pmksa->pmkid[i] = NULL;
os_free(pmksa);
}
/**
* pmksa_cache_auth_get - Fetch a PMKSA cache entry
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @spa: Supplicant address or %NULL to match any
* @pmkid: PMKID or %NULL to match any
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
const u8 *spa, const u8 *pmkid)
{
struct rsn_pmksa_cache_entry *entry;
if (pmkid)
entry = pmksa->pmkid[PMKID_HASH(pmkid)];
else
entry = pmksa->pmksa;
while (entry) {
if ((spa == NULL ||
os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
(pmkid == NULL ||
os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
return entry;
entry = pmkid ? entry->hnext : entry->next;
}
return NULL;
}
/**
* pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: PMKID
* Returns: Pointer to PMKSA cache entry or %NULL if no match was found
*
* Use opportunistic key caching (OKC) to find a PMK for a supplicant.
*/
struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
const u8 *pmkid)
{
struct rsn_pmksa_cache_entry *entry;
u8 new_pmkid[PMKID_LEN];
entry = pmksa->pmksa;
while (entry) {
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
wpa_key_mgmt_sha256(entry->akmp));
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
entry = entry->next;
}
return NULL;
}
/**
* pmksa_cache_auth_init - Initialize PMKSA cache
* @free_cb: Callback function to be called when a PMKSA cache entry is freed
* @ctx: Context pointer for free_cb function
* Returns: Pointer to PMKSA cache data or %NULL on failure
*/
struct rsn_pmksa_cache *
pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx), void *ctx)
{
struct rsn_pmksa_cache *pmksa;
pmksa = os_zalloc(sizeof(*pmksa));
if (pmksa) {
pmksa->free_cb = free_cb;
pmksa->ctx = ctx;
}
return pmksa;
}

View file

@ -0,0 +1,64 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PMKSA_CACHE_H
#define PMKSA_CACHE_H
#include "radius/radius.h"
/**
* struct rsn_pmksa_cache_entry - PMKSA cache entry
*/
struct rsn_pmksa_cache_entry {
struct rsn_pmksa_cache_entry *next, *hnext;
u8 pmkid[PMKID_LEN];
u8 pmk[PMK_LEN];
size_t pmk_len;
os_time_t expiration;
int akmp; /* WPA_KEY_MGMT_* */
u8 spa[ETH_ALEN];
u8 *identity;
size_t identity_len;
struct radius_class_data radius_class;
u8 eap_type_authsrv;
int vlan_id;
int opportunistic;
};
struct rsn_pmksa_cache;
struct rsn_pmksa_cache *
pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
void *ctx), void *ctx);
void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa);
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
const u8 *spa, const u8 *pmkid);
struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa,
const u8 *pmkid);
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
const struct rsn_pmksa_cache_entry *old_entry,
const u8 *aa, const u8 *pmkid);
void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol);
#endif /* PMKSA_CACHE_H */

View file

@ -0,0 +1,279 @@
/*
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#ifdef CONFIG_RSN_PREAUTH
#include "utils/common.h"
#include "utils/eloop.h"
#include "l2_packet/l2_packet.h"
#include "common/wpa_common.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ieee802_1x.h"
#include "sta_info.h"
#include "wpa_auth.h"
#include "preauth_auth.h"
#ifndef ETH_P_PREAUTH
#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
#endif /* ETH_P_PREAUTH */
static const int dot11RSNAConfigPMKLifetime = 43200;
struct rsn_preauth_interface {
struct rsn_preauth_interface *next;
struct hostapd_data *hapd;
struct l2_packet_data *l2;
char *ifname;
int ifindex;
};
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
{
struct rsn_preauth_interface *piface = ctx;
struct hostapd_data *hapd = piface->hapd;
struct ieee802_1x_hdr *hdr;
struct sta_info *sta;
struct l2_ethhdr *ethhdr;
wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
"from interface '%s'", piface->ifname);
if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
"(len=%lu)", (unsigned long) len);
return;
}
ethhdr = (struct l2_ethhdr *) buf;
hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
MACSTR, MAC2STR(ethhdr->h_dest));
return;
}
sta = ap_get_sta(hapd, ethhdr->h_source);
if (sta && (sta->flags & WLAN_STA_ASSOC)) {
wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
"STA " MACSTR, MAC2STR(sta->addr));
return;
}
if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
sta = ap_sta_add(hapd, ethhdr->h_source);
if (sta == NULL)
return;
sta->flags = WLAN_STA_PREAUTH;
ieee802_1x_new_station(hapd, sta);
if (sta->eapol_sm == NULL) {
ap_free_sta(hapd, sta);
sta = NULL;
} else {
sta->eapol_sm->radius_identifier = -1;
sta->eapol_sm->portValid = TRUE;
sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
}
}
if (sta == NULL)
return;
sta->preauth_iface = piface;
ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
len - sizeof(*ethhdr));
}
static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
{
struct rsn_preauth_interface *piface;
wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
piface = os_zalloc(sizeof(*piface));
if (piface == NULL)
return -1;
piface->hapd = hapd;
piface->ifname = os_strdup(ifname);
if (piface->ifname == NULL) {
goto fail1;
}
piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
rsn_preauth_receive, piface, 1);
if (piface->l2 == NULL) {
wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
"to ETH_P_PREAUTH");
goto fail2;
}
piface->next = hapd->preauth_iface;
hapd->preauth_iface = piface;
return 0;
fail2:
os_free(piface->ifname);
fail1:
os_free(piface);
return -1;
}
void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
{
struct rsn_preauth_interface *piface, *prev;
piface = hapd->preauth_iface;
hapd->preauth_iface = NULL;
while (piface) {
prev = piface;
piface = piface->next;
l2_packet_deinit(prev->l2);
os_free(prev->ifname);
os_free(prev);
}
}
int rsn_preauth_iface_init(struct hostapd_data *hapd)
{
char *tmp, *start, *end;
if (hapd->conf->rsn_preauth_interfaces == NULL)
return 0;
tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
if (tmp == NULL)
return -1;
start = tmp;
for (;;) {
while (*start == ' ')
start++;
if (*start == '\0')
break;
end = os_strchr(start, ' ');
if (end)
*end = '\0';
if (rsn_preauth_iface_add(hapd, start)) {
rsn_preauth_iface_deinit(hapd);
os_free(tmp);
return -1;
}
if (end)
start = end + 1;
else
break;
}
os_free(tmp);
return 0;
}
static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
MACSTR, MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
}
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success)
{
const u8 *key;
size_t len;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_INFO, "pre-authentication %s",
success ? "succeeded" : "failed");
key = ieee802_1x_get_key(sta->eapol_sm, &len);
if (len > PMK_LEN)
len = PMK_LEN;
if (success && key) {
if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
sta->addr,
dot11RSNAConfigPMKLifetime,
sta->eapol_sm) == 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
"added PMKSA cache entry (pre-auth)");
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
"failed to add PMKSA cache entry "
"(pre-auth)");
}
}
/*
* Finish STA entry removal from timeout in order to avoid freeing
* STA data before the caller has finished processing.
*/
eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
}
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len)
{
struct rsn_preauth_interface *piface;
struct l2_ethhdr *ethhdr;
piface = hapd->preauth_iface;
while (piface) {
if (piface == sta->preauth_iface)
break;
piface = piface->next;
}
if (piface == NULL) {
wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
"interface for " MACSTR, MAC2STR(sta->addr));
return;
}
ethhdr = os_malloc(sizeof(*ethhdr) + len);
if (ethhdr == NULL)
return;
os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
os_memcpy(ethhdr + 1, buf, len);
if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
sizeof(*ethhdr) + len) < 0) {
wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
"l2_packet_send\n");
}
os_free(ethhdr);
}
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
{
eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
}
#endif /* CONFIG_RSN_PREAUTH */

View file

@ -0,0 +1,58 @@
/*
* hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
* Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PREAUTH_H
#define PREAUTH_H
#ifdef CONFIG_RSN_PREAUTH
int rsn_preauth_iface_init(struct hostapd_data *hapd);
void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
int success);
void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
u8 *buf, size_t len);
void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_RSN_PREAUTH */
static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
{
}
static inline void rsn_preauth_finished(struct hostapd_data *hapd,
struct sta_info *sta,
int success)
{
}
static inline void rsn_preauth_send(struct hostapd_data *hapd,
struct sta_info *sta,
u8 *buf, size_t len)
{
}
static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
struct sta_info *sta)
{
}
#endif /* CONFIG_RSN_PREAUTH */
#endif /* PREAUTH_H */

View file

@ -0,0 +1,796 @@
/*
* hostapd / Station table
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "drivers/driver.h"
#include "p2p/p2p.h"
#include "hostapd.h"
#include "accounting.h"
#include "ieee802_1x.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
#include "preauth_auth.h"
#include "ap_config.h"
#include "beacon.h"
#include "ap_mlme.h"
#include "vlan_init.h"
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "sta_info.h"
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta);
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
#ifdef CONFIG_IEEE80211W
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_IEEE80211W */
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
void *ctx),
void *ctx)
{
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (cb(hapd, sta, ctx))
return 1;
}
return 0;
}
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
{
struct sta_info *s;
s = hapd->sta_hash[STA_HASH(sta)];
while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
s = s->hnext;
return s;
}
static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sta_info *tmp;
if (hapd->sta_list == sta) {
hapd->sta_list = sta->next;
return;
}
tmp = hapd->sta_list;
while (tmp != NULL && tmp->next != sta)
tmp = tmp->next;
if (tmp == NULL) {
wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
"list.", MAC2STR(sta->addr));
} else
tmp->next = sta->next;
}
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
{
sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
hapd->sta_hash[STA_HASH(sta->addr)] = sta;
}
static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
{
struct sta_info *s;
s = hapd->sta_hash[STA_HASH(sta->addr)];
if (s == NULL) return;
if (os_memcmp(s->addr, sta->addr, 6) == 0) {
hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
return;
}
while (s->hnext != NULL &&
os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
s = s->hnext;
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
" from hash table", MAC2STR(sta->addr));
}
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
{
int set_beacon = 0;
accounting_sta_stop(hapd, sta);
/* just in case */
ap_sta_set_authorized(hapd, sta, 0);
if (sta->flags & WLAN_STA_WDS)
hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
if (!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
if (sta->aid > 0)
hapd->sta_aid[(sta->aid - 1) / 32] &=
~BIT((sta->aid - 1) % 32);
hapd->num_sta--;
if (sta->nonerp_set) {
sta->nonerp_set = 0;
hapd->iface->num_sta_non_erp--;
if (hapd->iface->num_sta_non_erp == 0)
set_beacon++;
}
if (sta->no_short_slot_time_set) {
sta->no_short_slot_time_set = 0;
hapd->iface->num_sta_no_short_slot_time--;
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_slot_time == 0)
set_beacon++;
}
if (sta->no_short_preamble_set) {
sta->no_short_preamble_set = 0;
hapd->iface->num_sta_no_short_preamble--;
if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
&& hapd->iface->num_sta_no_short_preamble == 0)
set_beacon++;
}
if (sta->no_ht_gf_set) {
sta->no_ht_gf_set = 0;
hapd->iface->num_sta_ht_no_gf--;
}
if (sta->no_ht_set) {
sta->no_ht_set = 0;
hapd->iface->num_sta_no_ht--;
}
if (sta->ht_20mhz_set) {
sta->ht_20mhz_set = 0;
hapd->iface->num_sta_ht_20mhz--;
}
#ifdef CONFIG_P2P
if (sta->no_p2p_set) {
sta->no_p2p_set = 0;
hapd->num_sta_no_p2p--;
if (hapd->num_sta_no_p2p == 0)
hostapd_p2p_non_p2p_sta_disconnected(hapd);
}
#endif /* CONFIG_P2P */
#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
if (hostapd_ht_operation_update(hapd->iface) > 0)
set_beacon++;
#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
if (set_beacon)
ieee802_11_set_beacons(hapd->iface);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
rsn_preauth_free_station(hapd, sta);
#ifndef CONFIG_NO_RADIUS
radius_client_flush_auth(hapd->radius, sta->addr);
#endif /* CONFIG_NO_RADIUS */
os_free(sta->last_assoc_req);
os_free(sta->challenge);
#ifdef CONFIG_IEEE80211W
os_free(sta->sa_query_trans_id);
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_P2P
p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
#endif /* CONFIG_P2P */
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
os_free(sta->ht_capabilities);
os_free(sta);
}
void hostapd_free_stas(struct hostapd_data *hapd)
{
struct sta_info *sta, *prev;
sta = hapd->sta_list;
while (sta) {
prev = sta;
if (sta->flags & WLAN_STA_AUTH) {
mlme_deauthenticate_indication(
hapd, sta, WLAN_REASON_UNSPECIFIED);
}
sta = sta->next;
wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
MAC2STR(prev->addr));
ap_free_sta(hapd, prev);
}
}
/**
* ap_handle_timer - Per STA timer handler
* @eloop_ctx: struct hostapd_data *
* @timeout_ctx: struct sta_info *
*
* This function is called to check station activity and to remove inactive
* stations.
*/
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
unsigned long next_time = 0;
if (sta->timeout_next == STA_REMOVE) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"local deauth request");
ap_free_sta(hapd, sta);
return;
}
if ((sta->flags & WLAN_STA_ASSOC) &&
(sta->timeout_next == STA_NULLFUNC ||
sta->timeout_next == STA_DISASSOC)) {
int inactive_sec;
inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
if (inactive_sec == -1) {
wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not "
"get station info rom kernel driver for "
MACSTR, MAC2STR(sta->addr));
} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
sta->flags & WLAN_STA_ASSOC) {
/* station activity detected; reset timeout state */
wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
"active %is ago",
MAC2STR(sta->addr), inactive_sec);
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity -
inactive_sec;
} else {
wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
"inactive too long: %d sec, max allowed: %d",
MAC2STR(sta->addr), inactive_sec,
hapd->conf->ap_max_inactivity);
}
}
if ((sta->flags & WLAN_STA_ASSOC) &&
sta->timeout_next == STA_DISASSOC &&
!(sta->flags & WLAN_STA_PENDING_POLL)) {
wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data "
"poll", MAC2STR(sta->addr));
/* data nullfunc frame poll did not produce TX errors; assume
* station ACKed it */
sta->timeout_next = STA_NULLFUNC;
next_time = hapd->conf->ap_max_inactivity;
}
if (next_time) {
eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
sta);
return;
}
if (sta->timeout_next == STA_NULLFUNC &&
(sta->flags & WLAN_STA_ASSOC)) {
#ifndef CONFIG_NATIVE_WINDOWS
/* send data frame to poll STA and check whether this frame
* is ACKed */
struct ieee80211_hdr hdr;
wpa_printf(MSG_DEBUG, " Polling STA with data frame");
sta->flags |= WLAN_STA_PENDING_POLL;
os_memset(&hdr, 0, sizeof(hdr));
if (hapd->driver &&
os_strcmp(hapd->driver->name, "hostap") == 0) {
/*
* WLAN_FC_STYPE_NULLFUNC would be more appropriate,
* but it is apparently not retried so TX Exc events
* are not received for it.
*/
hdr.frame_control =
IEEE80211_FC(WLAN_FC_TYPE_DATA,
WLAN_FC_STYPE_DATA);
} else {
hdr.frame_control =
IEEE80211_FC(WLAN_FC_TYPE_DATA,
WLAN_FC_STYPE_NULLFUNC);
}
hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0)
perror("ap_handle_timer: send");
#endif /* CONFIG_NATIVE_WINDOWS */
} else if (sta->timeout_next != STA_REMOVE) {
int deauth = sta->timeout_next == STA_DEAUTH;
wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
deauth ? "deauthentication" : "disassociation",
MAC2STR(sta->addr));
if (deauth) {
hostapd_drv_sta_deauth(
hapd, sta->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
} else {
hostapd_drv_sta_disassoc(
hapd, sta->addr,
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
}
}
switch (sta->timeout_next) {
case STA_NULLFUNC:
sta->timeout_next = STA_DISASSOC;
eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
hapd, sta);
break;
case STA_DISASSOC:
sta->flags &= ~WLAN_STA_ASSOC;
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disassociated due to "
"inactivity");
sta->timeout_next = STA_DEAUTH;
eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
hapd, sta);
mlme_disassociate_indication(
hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
break;
case STA_DEAUTH:
case STA_REMOVE:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"inactivity");
if (!sta->acct_terminate_cause)
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
mlme_deauthenticate_indication(
hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
ap_free_sta(hapd, sta);
break;
}
}
static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
u8 addr[ETH_ALEN];
if (!(sta->flags & WLAN_STA_AUTH))
return;
mlme_deauthenticate_indication(hapd, sta,
WLAN_REASON_PREV_AUTH_NOT_VALID);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "deauthenticated due to "
"session timeout");
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
os_memcpy(addr, sta->addr, ETH_ALEN);
ap_free_sta(hapd, sta);
hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
}
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout)
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
"seconds", session_timeout);
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
hapd, sta);
}
void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
}
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
{
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
if (sta)
return sta;
wpa_printf(MSG_DEBUG, " New STA");
if (hapd->num_sta >= hapd->conf->max_num_sta) {
/* FIX: might try to remove some old STAs first? */
wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
hapd->num_sta, hapd->conf->max_num_sta);
return NULL;
}
sta = os_zalloc(sizeof(struct sta_info));
if (sta == NULL) {
wpa_printf(MSG_ERROR, "malloc failed");
return NULL;
}
sta->acct_interim_interval = hapd->conf->acct_interim_interval;
/* initialize STA info data */
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
ap_handle_timer, hapd, sta);
os_memcpy(sta->addr, addr, ETH_ALEN);
sta->next = hapd->sta_list;
hapd->sta_list = sta;
hapd->num_sta++;
ap_sta_hash_add(hapd, sta);
sta->ssid = &hapd->conf->ssid;
ap_sta_remove_in_other_bss(hapd, sta);
return sta;
}
static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
{
ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
MAC2STR(sta->addr));
if (hostapd_drv_sta_remove(hapd, sta->addr) &&
sta->flags & WLAN_STA_ASSOC) {
wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
" from kernel driver.", MAC2STR(sta->addr));
return -1;
}
return 0;
}
static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
struct sta_info *sta)
{
struct hostapd_iface *iface = hapd->iface;
size_t i;
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *bss = iface->bss[i];
struct sta_info *sta2;
/* bss should always be set during operation, but it may be
* NULL during reconfiguration. Assume the STA is not
* associated to another BSS in that case to avoid NULL pointer
* dereferences. */
if (bss == hapd || bss == NULL)
continue;
sta2 = ap_get_sta(bss, sta->addr);
if (!sta2)
continue;
ap_sta_disconnect(bss, sta2, sta2->addr,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
}
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~WLAN_STA_ASSOC;
ap_sta_remove(hapd, sta);
sta->timeout_next = STA_DEAUTH;
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
mlme_disassociate_indication(hapd, sta, reason);
}
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason)
{
wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
hapd->conf->iface, MAC2STR(sta->addr));
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
ap_sta_remove(hapd, sta);
sta->timeout_next = STA_REMOVE;
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
ap_handle_timer, hapd, sta);
accounting_sta_stop(hapd, sta);
ieee802_1x_free_station(sta);
mlme_deauthenticate_indication(hapd, sta, reason);
}
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
{
#ifndef CONFIG_NO_VLAN
const char *iface;
struct hostapd_vlan *vlan = NULL;
int ret;
/*
* Do not proceed furthur if the vlan id remains same. We do not want
* duplicate dynamic vlan entries.
*/
if (sta->vlan_id == old_vlanid)
return 0;
/*
* During 1x reauth, if the vlan id changes, then remove the old id and
* proceed furthur to add the new one.
*/
if (old_vlanid > 0)
vlan_remove_dynamic(hapd, old_vlanid);
iface = hapd->conf->iface;
if (sta->ssid->vlan[0])
iface = sta->ssid->vlan;
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
vlan = hapd->conf->vlan;
while (vlan) {
if (vlan->vlan_id == sta->vlan_id ||
vlan->vlan_id == VLAN_ID_WILDCARD) {
iface = vlan->ifname;
break;
}
vlan = vlan->next;
}
}
if (sta->vlan_id > 0 && vlan == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
"binding station to (vlan_id=%d)",
sta->vlan_id);
return -1;
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
if (vlan == NULL) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not add "
"dynamic VLAN interface for vlan_id=%d",
sta->vlan_id);
return -1;
}
iface = vlan->ifname;
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
"configure encryption for dynamic VLAN "
"interface for vlan_id=%d",
sta->vlan_id);
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
"interface '%s'", iface);
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
if (sta->vlan_id > 0) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "updated existing "
"dynamic VLAN interface '%s'", iface);
}
/*
* Update encryption configuration for statically generated
* VLAN interface. This is only used for static WEP
* configuration for the case where hostapd did not yet know
* which keys are to be used when the interface was added.
*/
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
"configure encryption for VLAN "
"interface for vlan_id=%d",
sta->vlan_id);
}
}
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
if (ret < 0) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
"entry to vlan_id=%d", sta->vlan_id);
}
return ret;
#else /* CONFIG_NO_VLAN */
return 0;
#endif /* CONFIG_NO_VLAN */
}
#ifdef CONFIG_IEEE80211W
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
{
u32 tu;
struct os_time now, passed;
os_get_time(&now);
os_time_sub(&now, &sta->sa_query_start, &passed);
tu = (passed.sec * 1000000 + passed.usec) / 1024;
if (hapd->conf->assoc_sa_query_max_timeout < tu) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"association SA Query timed out");
sta->sa_query_timed_out = 1;
os_free(sta->sa_query_trans_id);
sta->sa_query_trans_id = NULL;
sta->sa_query_count = 0;
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
return 1;
}
return 0;
}
static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
unsigned int timeout, sec, usec;
u8 *trans_id, *nbuf;
if (sta->sa_query_count > 0 &&
ap_check_sa_query_timeout(hapd, sta))
return;
nbuf = os_realloc(sta->sa_query_trans_id,
(sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (sta->sa_query_count == 0) {
/* Starting a new SA Query procedure */
os_get_time(&sta->sa_query_start);
}
trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
sta->sa_query_trans_id = nbuf;
sta->sa_query_count++;
os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
timeout = hapd->conf->assoc_sa_query_retry_timeout;
sec = ((timeout / 1000) * 1024) / 1000;
usec = (timeout % 1000) * 1024;
eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"association SA Query attempt %d", sta->sa_query_count);
#ifdef NEED_AP_MLME
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
#endif /* NEED_AP_MLME */
}
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
{
ap_sa_query_timer(hapd, sta);
}
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
{
eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
os_free(sta->sa_query_trans_id);
sta->sa_query_trans_id = NULL;
sta->sa_query_count = 0;
}
#endif /* CONFIG_IEEE80211W */
void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
int authorized)
{
if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
return;
if (authorized)
sta->flags |= WLAN_STA_AUTHORIZED;
else
sta->flags &= ~WLAN_STA_AUTHORIZED;
if (hapd->sta_authorized_cb)
hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
sta->addr, authorized);
}
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason)
{
if (sta == NULL && addr)
sta = ap_get_sta(hapd, addr);
if (addr)
hostapd_drv_sta_deauth(hapd, addr, reason);
if (sta == NULL)
return;
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
eloop_cancel_timeout(ap_handle_timer, hapd, sta);
eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
sta->timeout_next = STA_REMOVE;
}

View file

@ -0,0 +1,165 @@
/*
* hostapd / Station table
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef STA_INFO_H
#define STA_INFO_H
/* STA flags */
#define WLAN_STA_AUTH BIT(0)
#define WLAN_STA_ASSOC BIT(1)
#define WLAN_STA_PS BIT(2)
#define WLAN_STA_TIM BIT(3)
#define WLAN_STA_PERM BIT(4)
#define WLAN_STA_AUTHORIZED BIT(5)
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
#define WLAN_STA_PREAUTH BIT(8)
#define WLAN_STA_WMM BIT(9)
#define WLAN_STA_MFP BIT(10)
#define WLAN_STA_HT BIT(11)
#define WLAN_STA_WPS BIT(12)
#define WLAN_STA_MAYBE_WPS BIT(13)
#define WLAN_STA_WDS BIT(14)
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
#define WLAN_STA_NONERP BIT(31)
/* Maximum number of supported rates (from both Supported Rates and Extended
* Supported Rates IEs). */
#define WLAN_SUPP_RATES_MAX 32
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
u8 addr[6];
u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
u32 flags; /* Bitfield of WLAN_STA_* */
u16 capability;
u16 listen_interval; /* or beacon_int for APs */
u8 supported_rates[WLAN_SUPP_RATES_MAX];
int supported_rates_len;
unsigned int nonerp_set:1;
unsigned int no_short_slot_time_set:1;
unsigned int no_short_preamble_set:1;
unsigned int no_ht_gf_set:1;
unsigned int no_ht_set:1;
unsigned int ht_20mhz_set:1;
unsigned int no_p2p_set:1;
u16 auth_alg;
u8 previous_ap[6];
enum {
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
} timeout_next;
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
/* IEEE 802.11f (IAPP) related data */
struct ieee80211_mgmt *last_assoc_req;
u32 acct_session_id_hi;
u32 acct_session_id_lo;
time_t acct_session_start;
int acct_session_started;
int acct_terminate_cause; /* Acct-Terminate-Cause */
int acct_interim_interval; /* Acct-Interim-Interval */
unsigned long last_rx_bytes;
unsigned long last_tx_bytes;
u32 acct_input_gigawords; /* Acct-Input-Gigawords */
u32 acct_output_gigawords; /* Acct-Output-Gigawords */
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
struct wpa_state_machine *wpa_sm;
struct rsn_preauth_interface *preauth_iface;
struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
int vlan_id;
struct ieee80211_ht_capabilities *ht_capabilities;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
* 0 = no SA Query in progress */
int sa_query_timed_out;
u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
* sa_query_count octets of pending SA Query
* transaction identifiers */
struct os_time sa_query_start;
#endif /* CONFIG_IEEE80211W */
struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
};
/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
* passed since last received frame from the station, a nullfunc data frame is
* sent to the station. If this frame is not acknowledged and no other frames
* have been received, the station will be disassociated after
* AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
* after AP_DEAUTH_DELAY seconds has passed after disassociation. */
#define AP_MAX_INACTIVITY (5 * 60)
#define AP_DISASSOC_DELAY (1)
#define AP_DEAUTH_DELAY (1)
/* Number of seconds to keep STA entry with Authenticated flag after it has
* been disassociated. */
#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
/* Number of seconds to keep STA entry after it has been deauthenticated. */
#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
struct hostapd_data;
int ap_for_each_sta(struct hostapd_data *hapd,
int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
void *ctx),
void *ctx);
struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
void hostapd_free_stas(struct hostapd_data *hapd);
void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
u32 session_timeout);
void ap_sta_no_session_timeout(struct hostapd_data *hapd,
struct sta_info *sta);
struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
u16 reason);
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid);
void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *addr, u16 reason);
void ap_sta_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
static inline int ap_sta_is_authorized(struct sta_info *sta)
{
return sta->flags & WLAN_STA_AUTHORIZED;
}
#endif /* STA_INFO_H */

View file

@ -0,0 +1,94 @@
/*
* hostapd / TKIP countermeasures
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "common/ieee802_11_defs.h"
#include "hostapd.h"
#include "sta_info.h"
#include "ap_mlme.h"
#include "wpa_auth.h"
#include "ap_drv_ops.h"
#include "tkip_countermeasures.h"
static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
void *timeout_ctx)
{
struct hostapd_data *hapd = eloop_ctx;
hapd->tkip_countermeasures = 0;
hostapd_drv_set_countermeasures(hapd, 0);
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
}
static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
{
struct sta_info *sta;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
wpa_auth_countermeasures_start(hapd->wpa_auth);
hapd->tkip_countermeasures = 1;
hostapd_drv_set_countermeasures(hapd, 1);
wpa_gtk_rekey(hapd->wpa_auth);
eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
hapd, NULL);
for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
hostapd_drv_sta_deauth(hapd, sta->addr,
WLAN_REASON_MICHAEL_MIC_FAILURE);
ap_sta_set_authorized(hapd, sta, 0);
sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
hostapd_drv_sta_remove(hapd, sta->addr);
}
}
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
{
time_t now;
if (addr && local) {
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta != NULL) {
wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
"Michael MIC failure detected in "
"received frame");
mlme_michaelmicfailure_indication(hapd, addr);
} else {
wpa_printf(MSG_DEBUG,
"MLME-MICHAELMICFAILURE.indication "
"for not associated STA (" MACSTR
") ignored", MAC2STR(addr));
return;
}
}
time(&now);
if (now > hapd->michael_mic_failure + 60) {
hapd->michael_mic_failures = 1;
} else {
hapd->michael_mic_failures++;
if (hapd->michael_mic_failures > 1)
ieee80211_tkip_countermeasures_start(hapd);
}
hapd->michael_mic_failure = now;
}

View file

@ -0,0 +1,20 @@
/*
* hostapd / TKIP countermeasures
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef TKIP_COUNTERMEASURES_H
#define TKIP_COUNTERMEASURES_H
void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
#endif /* TKIP_COUNTERMEASURES_H */

View file

@ -0,0 +1,88 @@
/*
* AP mode helper functions
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "sta_info.h"
#include "hostapd.h"
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
int (*cb)(void *ctx, const u8 *sa,
const u8 *ie, size_t ie_len),
void *ctx)
{
struct hostapd_probereq_cb *n;
n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) *
sizeof(struct hostapd_probereq_cb));
if (n == NULL)
return -1;
hapd->probereq_cb = n;
n = &hapd->probereq_cb[hapd->num_probereq_cb];
hapd->num_probereq_cb++;
n->cb = cb;
n->ctx = ctx;
return 0;
}
struct prune_data {
struct hostapd_data *hapd;
const u8 *addr;
};
static int prune_associations(struct hostapd_iface *iface, void *ctx)
{
struct prune_data *data = ctx;
struct sta_info *osta;
struct hostapd_data *ohapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
osta = ap_get_sta(ohapd, data->addr);
if (!osta)
continue;
ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
}
return 0;
}
/**
* hostapd_prune_associations - Remove extraneous associations
* @hapd: Pointer to BSS data for the most recent association
* @addr: Associated STA address
*
* This function looks through all radios and BSS's for previous
* (stale) associations of STA. If any are found they are removed.
*/
void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
{
struct prune_data data;
data.hapd = hapd;
data.addr = addr;
if (hapd->iface->for_each_interface)
hapd->iface->for_each_interface(hapd->iface->interfaces,
prune_associations, &data);
}

View file

@ -0,0 +1,905 @@
/*
* hostapd / VLAN initialization
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "vlan_init.h"
#ifdef CONFIG_FULL_DYNAMIC_VLAN
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <linux/if_vlan.h>
#include <linux/if_bridge.h>
#include "drivers/priv_netlink.h"
#include "utils/eloop.h"
struct full_dynamic_vlan {
int s; /* socket on which to listen for new/removed interfaces. */
};
static int ifconfig_helper(const char *if_name, int up)
{
int fd;
struct ifreq ifr;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
"for interface %s: %s",
__func__, if_name, strerror(errno));
close(fd);
return -1;
}
if (up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
"for interface %s (up=%d): %s",
__func__, if_name, up, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
static int ifconfig_up(const char *if_name)
{
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
return ifconfig_helper(if_name, 1);
}
static int ifconfig_down(const char *if_name)
{
wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
return ifconfig_helper(if_name, 0);
}
/*
* These are only available in recent linux headers (without the leading
* underscore).
*/
#define _GET_VLAN_REALDEV_NAME_CMD 8
#define _GET_VLAN_VID_CMD 9
/* This value should be 256 ONLY. If it is something else, then hostapd
* might crash!, as this value has been hard-coded in 2.4.x kernel
* bridging code.
*/
#define MAX_BR_PORTS 256
static int br_delif(const char *br_name, const char *if_name)
{
int fd;
struct ifreq ifr;
unsigned long args[2];
int if_index;
wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
if_index = if_nametoindex(if_name);
if (if_index == 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
"interface index for '%s'",
__func__, if_name);
close(fd);
return -1;
}
args[0] = BRCTL_DEL_IF;
args[1] = if_index;
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (__caddr_t) args;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
/* No error if interface already removed. */
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
"BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
"%s", __func__, br_name, if_name, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add interface 'if_name' to the bridge 'br_name'
returns -1 on error
returns 1 if the interface is already part of the bridge
returns 0 otherwise
*/
static int br_addif(const char *br_name, const char *if_name)
{
int fd;
struct ifreq ifr;
unsigned long args[2];
int if_index;
wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
if_index = if_nametoindex(if_name);
if (if_index == 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
"interface index for '%s'",
__func__, if_name);
close(fd);
return -1;
}
args[0] = BRCTL_ADD_IF;
args[1] = if_index;
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (__caddr_t) args;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
if (errno == EBUSY) {
/* The interface is already added. */
close(fd);
return 1;
}
wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
"BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
"%s", __func__, br_name, if_name, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
static int br_delbr(const char *br_name)
{
int fd;
unsigned long arg[2];
wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
arg[0] = BRCTL_DEL_BRIDGE;
arg[1] = (unsigned long) br_name;
if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
/* No error if bridge already removed. */
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
"%s: %s", __func__, br_name, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add a bridge with the name 'br_name'.
returns -1 on error
returns 1 if the bridge already exists
returns 0 otherwise
*/
static int br_addbr(const char *br_name)
{
int fd;
unsigned long arg[4];
struct ifreq ifr;
wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
arg[0] = BRCTL_ADD_BRIDGE;
arg[1] = (unsigned long) br_name;
if (ioctl(fd, SIOCGIFBR, arg) < 0) {
if (errno == EEXIST) {
/* The bridge is already added. */
close(fd);
return 1;
} else {
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
"failed for %s: %s",
__func__, br_name, strerror(errno));
close(fd);
return -1;
}
}
/* Decrease forwarding delay to avoid EAPOL timeouts. */
os_memset(&ifr, 0, sizeof(ifr));
os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
arg[1] = 1;
arg[2] = 0;
arg[3] = 0;
ifr.ifr_data = (char *) &arg;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: "
"BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
"%s: %s", __func__, br_name, strerror(errno));
/* Continue anyway */
}
close(fd);
return 0;
}
static int br_getnumports(const char *br_name)
{
int fd;
int i;
int port_cnt = 0;
unsigned long arg[4];
int ifindices[MAX_BR_PORTS];
struct ifreq ifr;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
arg[0] = BRCTL_GET_PORT_LIST;
arg[1] = (unsigned long) ifindices;
arg[2] = MAX_BR_PORTS;
arg[3] = 0;
os_memset(ifindices, 0, sizeof(ifindices));
os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
ifr.ifr_data = (__caddr_t) arg;
if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
"failed for %s: %s",
__func__, br_name, strerror(errno));
close(fd);
return -1;
}
for (i = 1; i < MAX_BR_PORTS; i++) {
if (ifindices[i] > 0) {
port_cnt++;
}
}
close(fd);
return port_cnt;
}
static int vlan_rem(const char *if_name)
{
int fd;
struct vlan_ioctl_args if_request;
wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
if_name);
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
if_request.cmd = DEL_VLAN_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
"%s", __func__, if_name, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
/*
Add a vlan interface with VLAN ID 'vid' and tagged interface
'if_name'.
returns -1 on error
returns 1 if the interface already exists
returns 0 otherwise
*/
static int vlan_add(const char *if_name, int vid)
{
int fd;
struct vlan_ioctl_args if_request;
wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
if_name, vid);
ifconfig_up(if_name);
if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
if_name);
return -1;
}
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
/* Determine if a suitable vlan device already exists. */
os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
vid);
if_request.cmd = _GET_VLAN_VID_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
if (if_request.u.VID == vid) {
if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
os_strncmp(if_request.u.device2, if_name,
sizeof(if_request.u.device2)) == 0) {
close(fd);
wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
"if_name %s exists already",
if_request.device1);
return 1;
}
}
}
/* A suitable vlan device does not already exist, add one. */
os_memset(&if_request, 0, sizeof(if_request));
os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
if_request.u.VID = vid;
if_request.cmd = ADD_VLAN_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
"%s",
__func__, if_request.device1, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
static int vlan_set_name_type(unsigned int name_type)
{
int fd;
struct vlan_ioctl_args if_request;
wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
name_type);
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
"failed: %s", __func__, strerror(errno));
return -1;
}
os_memset(&if_request, 0, sizeof(if_request));
if_request.u.name_type = name_type;
if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
"name_type=%u failed: %s",
__func__, name_type, strerror(errno));
close(fd);
return -1;
}
close(fd);
return 0;
}
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
{
char vlan_ifname[IFNAMSIZ];
char br_name[IFNAMSIZ];
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
vlan->vlan_id);
if (!br_addbr(br_name))
vlan->clean |= DVLAN_CLEAN_BR;
ifconfig_up(br_name);
if (tagged_interface) {
if (!vlan_add(tagged_interface, vlan->vlan_id))
vlan->clean |= DVLAN_CLEAN_VLAN;
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
if (!br_addif(br_name, vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
ifconfig_up(vlan_ifname);
}
if (!br_addif(br_name, ifname))
vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
ifconfig_up(ifname);
break;
}
vlan = vlan->next;
}
}
static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
{
char vlan_ifname[IFNAMSIZ];
char br_name[IFNAMSIZ];
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
first = prev = vlan;
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
os_snprintf(br_name, sizeof(br_name), "brvlan%d",
vlan->vlan_id);
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
br_delif(br_name, vlan->ifname);
if (tagged_interface) {
os_snprintf(vlan_ifname, sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
ifconfig_down(vlan_ifname);
if (vlan->clean & DVLAN_CLEAN_VLAN)
vlan_rem(vlan_ifname);
}
if ((vlan->clean & DVLAN_CLEAN_BR) &&
br_getnumports(br_name) == 0) {
ifconfig_down(br_name);
br_delbr(br_name);
}
if (vlan == first) {
hapd->conf->vlan = vlan->next;
} else {
prev->next = vlan->next;
}
os_free(vlan);
break;
}
prev = vlan;
vlan = vlan->next;
}
}
static void
vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
struct hostapd_data *hapd)
{
struct ifinfomsg *ifi;
int attrlen, nlmsg_len, rta_len;
struct rtattr *attr;
if (len < sizeof(*ifi))
return;
ifi = NLMSG_DATA(h);
nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
attrlen = h->nlmsg_len - nlmsg_len;
if (attrlen < 0)
return;
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
rta_len = RTA_ALIGN(sizeof(struct rtattr));
while (RTA_OK(attr, attrlen)) {
char ifname[IFNAMSIZ + 1];
if (attr->rta_type == IFLA_IFNAME) {
int n = attr->rta_len - rta_len;
if (n < 0)
break;
os_memset(ifname, 0, sizeof(ifname));
if ((size_t) n > sizeof(ifname))
n = sizeof(ifname);
os_memcpy(ifname, ((char *) attr) + rta_len, n);
if (del)
vlan_dellink(ifname, hapd);
else
vlan_newlink(ifname, hapd);
}
attr = RTA_NEXT(attr, attrlen);
}
}
static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
char buf[8192];
int left;
struct sockaddr_nl from;
socklen_t fromlen;
struct nlmsghdr *h;
struct hostapd_data *hapd = eloop_ctx;
fromlen = sizeof(from);
left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
(struct sockaddr *) &from, &fromlen);
if (left < 0) {
if (errno != EINTR && errno != EAGAIN)
wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
__func__, strerror(errno));
return;
}
h = (struct nlmsghdr *) buf;
while (left >= (int) sizeof(*h)) {
int len, plen;
len = h->nlmsg_len;
plen = len - sizeof(*h);
if (len > left || plen < 0) {
wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
"message: len=%d left=%d plen=%d",
len, left, plen);
break;
}
switch (h->nlmsg_type) {
case RTM_NEWLINK:
vlan_read_ifnames(h, plen, 0, hapd);
break;
case RTM_DELLINK:
vlan_read_ifnames(h, plen, 1, hapd);
break;
}
len = NLMSG_ALIGN(len);
left -= len;
h = (struct nlmsghdr *) ((char *) h + len);
}
if (left > 0) {
wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
"netlink message", __func__, left);
}
}
static struct full_dynamic_vlan *
full_dynamic_vlan_init(struct hostapd_data *hapd)
{
struct sockaddr_nl local;
struct full_dynamic_vlan *priv;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
return NULL;
vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (priv->s < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
"NETLINK_ROUTE) failed: %s",
__func__, strerror(errno));
os_free(priv);
return NULL;
}
os_memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_groups = RTMGRP_LINK;
if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
__func__, strerror(errno));
close(priv->s);
os_free(priv);
return NULL;
}
if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
{
close(priv->s);
os_free(priv);
return NULL;
}
return priv;
}
static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
{
if (priv == NULL)
return;
eloop_unregister_read_sock(priv->s);
close(priv->s);
os_free(priv);
}
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid, const char *dyn_vlan)
{
int i;
if (dyn_vlan == NULL)
return 0;
/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
* functions for setting up dynamic broadcast keys. */
for (i = 0; i < 4; i++) {
if (mssid->wep.key[i] &&
hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
i == mssid->wep.idx, NULL, 0,
mssid->wep.key[i], mssid->wep.len[i]))
{
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
"encryption for dynamic VLAN");
return -1;
}
}
return 0;
}
static int vlan_dynamic_add(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
while (vlan) {
if (vlan->vlan_id != VLAN_ID_WILDCARD) {
if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
if (errno != EEXIST) {
wpa_printf(MSG_ERROR, "VLAN: Could "
"not add VLAN %s: %s",
vlan->ifname,
strerror(errno));
return -1;
}
}
#ifdef CONFIG_FULL_DYNAMIC_VLAN
ifconfig_up(vlan->ifname);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
vlan = vlan->next;
}
return 0;
}
static void vlan_dynamic_remove(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
struct hostapd_vlan *next;
while (vlan) {
next = vlan->next;
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
hostapd_vlan_if_remove(hapd, vlan->ifname)) {
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
"iface: %s: %s",
vlan->ifname, strerror(errno));
}
#ifdef CONFIG_FULL_DYNAMIC_VLAN
if (vlan->clean)
vlan_dellink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
vlan = next;
}
}
int vlan_init(struct hostapd_data *hapd)
{
#ifdef CONFIG_FULL_DYNAMIC_VLAN
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
if (vlan_dynamic_add(hapd, hapd->conf->vlan))
return -1;
return 0;
}
void vlan_deinit(struct hostapd_data *hapd)
{
vlan_dynamic_remove(hapd, hapd->conf->vlan);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
int vlan_id)
{
struct hostapd_vlan *n;
char *ifname, *pos;
if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
__func__, vlan_id, vlan->ifname);
ifname = os_strdup(vlan->ifname);
if (ifname == NULL)
return NULL;
pos = os_strchr(ifname, '#');
if (pos == NULL) {
os_free(ifname);
return NULL;
}
*pos++ = '\0';
n = os_zalloc(sizeof(*n));
if (n == NULL) {
os_free(ifname);
return NULL;
}
n->vlan_id = vlan_id;
n->dynamic_vlan = 1;
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
pos);
os_free(ifname);
if (hostapd_vlan_if_add(hapd, n->ifname)) {
os_free(n);
return NULL;
}
n->next = hapd->conf->vlan;
hapd->conf->vlan = n;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
ifconfig_up(n->ifname);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
return n;
}
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
{
struct hostapd_vlan *vlan;
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
return 1;
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
vlan = hapd->conf->vlan;
while (vlan) {
if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan--;
break;
}
vlan = vlan->next;
}
if (vlan == NULL)
return 1;
if (vlan->dynamic_vlan == 0)
hostapd_vlan_if_remove(hapd, vlan->ifname);
return 0;
}

View file

@ -0,0 +1,59 @@
/*
* hostapd / VLAN initialization
* Copyright 2003, Instant802 Networks, Inc.
* Copyright 2005, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef VLAN_INIT_H
#define VLAN_INIT_H
#ifndef CONFIG_NO_VLAN
int vlan_init(struct hostapd_data *hapd);
void vlan_deinit(struct hostapd_data *hapd);
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
int vlan_id);
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid,
const char *dyn_vlan);
#else /* CONFIG_NO_VLAN */
static inline int vlan_init(struct hostapd_data *hapd)
{
return 0;
}
static inline void vlan_deinit(struct hostapd_data *hapd)
{
}
static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
int vlan_id)
{
return NULL;
}
static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
{
return -1;
}
static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid,
const char *dyn_vlan)
{
return -1;
}
#endif /* CONFIG_NO_VLAN */
#endif /* VLAN_INIT_H */

327
hostapd-0.8/src/ap/wmm.c Normal file
View file

@ -0,0 +1,327 @@
/*
* hostapd / WMM (Wi-Fi Multimedia)
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "wmm.h"
/* TODO: maintain separate sequence and fragment numbers for each AC
* TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
* if only WMM stations are receiving a certain group */
static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
{
u8 ret;
ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK;
if (acm)
ret |= WMM_AC_ACM;
ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK;
return ret;
}
static inline u8 wmm_ecw(int ecwmin, int ecwmax)
{
return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) |
((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK);
}
/*
* Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
* Response frames.
*/
u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
struct wmm_parameter_element *wmm =
(struct wmm_parameter_element *) (pos + 2);
int e;
if (!hapd->conf->wmm_enabled)
return eid;
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
wmm->oui[0] = 0x00;
wmm->oui[1] = 0x50;
wmm->oui[2] = 0xf2;
wmm->oui_type = WMM_OUI_TYPE;
wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
wmm->version = WMM_VERSION;
wmm->qos_info = hapd->parameter_set_count & 0xf;
if (hapd->conf->wmm_uapsd)
wmm->qos_info |= 0x80;
wmm->reserved = 0;
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
struct wmm_ac_parameter *ac = &wmm->ac[e];
struct hostapd_wmm_ac_params *acp =
&hapd->iconf->wmm_ac_params[e];
ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
acp->admission_control_mandatory,
e);
ac->cw = wmm_ecw(acp->cwmin, acp->cwmax);
ac->txop_limit = host_to_le16(acp->txop_limit);
}
pos = (u8 *) (wmm + 1);
eid[1] = pos - eid - 2; /* element length */
return pos;
}
/* This function is called when a station sends an association request with
* WMM info element. The function returns zero on success or non-zero on any
* error in WMM element. eid does not include Element ID and Length octets. */
int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
{
struct wmm_information_element *wmm;
wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len);
if (len < sizeof(struct wmm_information_element)) {
wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
(unsigned long) len);
return -1;
}
wmm = (struct wmm_information_element *) eid;
wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x "
"OUI type %d OUI sub-type %d version %d QoS info 0x%x",
wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type,
wmm->oui_subtype, wmm->version, wmm->qos_info);
if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
wmm->version != WMM_VERSION) {
wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
return -1;
}
return 0;
}
static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
const struct wmm_tspec_element *tspec,
u8 action_code, u8 dialogue_token, u8 status_code)
{
u8 buf[256];
struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
struct wmm_tspec_element *t = (struct wmm_tspec_element *)
m->u.action.u.wmm_action.variable;
int len;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"action response - reason %d", status_code);
os_memset(buf, 0, sizeof(buf));
m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(m->da, addr, ETH_ALEN);
os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
m->u.action.category = WLAN_ACTION_WMM;
m->u.action.u.wmm_action.action_code = action_code;
m->u.action.u.wmm_action.dialog_token = dialogue_token;
m->u.action.u.wmm_action.status_code = status_code;
os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
if (hostapd_drv_send_mlme(hapd, m, len) < 0)
perror("wmm_send_action: send");
}
int wmm_process_tspec(struct wmm_tspec_element *tspec)
{
int medium_time, pps, duration;
int up, psb, dir, tid;
u16 val, surplus;
up = (tspec->ts_info[1] >> 3) & 0x07;
psb = (tspec->ts_info[1] >> 2) & 0x01;
dir = (tspec->ts_info[0] >> 5) & 0x03;
tid = (tspec->ts_info[0] >> 1) & 0x0f;
wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
up, psb, dir, tid);
val = le_to_host16(tspec->nominal_msdu_size);
wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
le_to_host32(tspec->mean_data_rate));
wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
le_to_host32(tspec->minimum_phy_rate));
val = le_to_host16(tspec->surplus_bandwidth_allowance);
wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
val >> 13, 10000 * (val & 0x1fff) / 0x2000);
val = le_to_host16(tspec->nominal_msdu_size);
if (val == 0) {
wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
}
/* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */
pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d",
pps);
if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
}
duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
(le_to_host32(tspec->minimum_phy_rate) / 1000000) +
50 /* FIX: proper SIFS + ACK duration */;
/* unsigned binary number with an implicit binary point after the
* leftmost 3 bits, i.e., 0x2000 = 1.0 */
surplus = le_to_host16(tspec->surplus_bandwidth_allowance);
if (surplus <= 0x2000) {
wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
"greater than unity");
return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
}
medium_time = surplus * pps * duration / 0x2000;
wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
/*
* TODO: store list of granted (and still active) TSPECs and check
* whether there is available medium time for this request. For now,
* just refuse requests that would by themselves take very large
* portion of the available bandwidth.
*/
if (medium_time > 750000) {
wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
"75%% of available bandwidth");
return WMM_ADDTS_STATUS_REFUSED;
}
/* Convert to 32 microseconds per second unit */
tspec->medium_time = host_to_le16(medium_time / 32);
return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
}
static void wmm_addts_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,
struct wmm_tspec_element *tspec, size_t len)
{
const u8 *end = ((const u8 *) mgmt) + len;
int res;
if ((const u8 *) (tspec + 1) > end) {
wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
return;
}
wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
"from " MACSTR,
mgmt->u.action.u.wmm_action.dialog_token,
MAC2STR(mgmt->sa));
res = wmm_process_tspec(tspec);
wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
mgmt->u.action.u.wmm_action.dialog_token, res);
}
void hostapd_wmm_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len)
{
int action_code;
int left = len - IEEE80211_HDRLEN - 4;
const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4;
struct ieee802_11_elems elems;
struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
/* check that the request comes from a valid station */
if (!sta ||
(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) !=
(WLAN_STA_ASSOC | WLAN_STA_WMM)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"wmm action received is not from associated wmm"
" station");
/* TODO: respond with action frame refused status code */
return;
}
/* extract the tspec info element */
if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"hostapd_wmm_action - could not parse wmm "
"action");
/* TODO: respond with action frame invalid parameters status
* code */
return;
}
if (!elems.wmm_tspec ||
elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"hostapd_wmm_action - missing or wrong length "
"tspec");
/* TODO: respond with action frame invalid parameters status
* code */
return;
}
/* TODO: check the request is for an AC with ACM set, if not, refuse
* request */
action_code = mgmt->u.action.u.wmm_action.action_code;
switch (action_code) {
case WMM_ACTION_CODE_ADDTS_REQ:
wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *)
(elems.wmm_tspec - 2), len);
return;
#if 0
/* TODO: needed for client implementation */
case WMM_ACTION_CODE_ADDTS_RESP:
wmm_setup_request(hapd, mgmt, len);
return;
/* TODO: handle station teardown requests */
case WMM_ACTION_CODE_DELTS:
wmm_teardown(hapd, mgmt, len);
return;
#endif
}
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"hostapd_wmm_action - unknown action code %d",
action_code);
}

29
hostapd-0.8/src/ap/wmm.h Normal file
View file

@ -0,0 +1,29 @@
/*
* hostapd / WMM (Wi-Fi Multimedia)
* Copyright 2002-2003, Instant802 Networks, Inc.
* Copyright 2005-2006, Devicescape Software, Inc.
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WME_H
#define WME_H
struct ieee80211_mgmt;
struct wmm_tspec_element;
u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid);
int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid,
size_t len);
void hostapd_wmm_action(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len);
int wmm_process_tspec(struct wmm_tspec_element *tspec);
#endif /* WME_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,285 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_AUTH_H
#define WPA_AUTH_H
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition
*/
struct ft_rrb_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */
le16 action_length; /* little endian length of action_frame */
u8 ap_address[ETH_ALEN];
/*
* Followed by action_length bytes of FT Action frame (from Category
* field to the end of Action Frame body.
*/
} STRUCT_PACKED;
#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1
#define FT_PACKET_REQUEST 0
#define FT_PACKET_RESPONSE 1
/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
#define FT_PACKET_R0KH_R1KH_PULL 200
#define FT_PACKET_R0KH_R1KH_RESP 201
#define FT_PACKET_R0KH_R1KH_PUSH 202
#define FT_R0KH_R1KH_PULL_DATA_LEN 44
#define FT_R0KH_R1KH_RESP_DATA_LEN 76
#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
struct ft_r0kh_r1kh_pull_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
le16 data_length; /* little endian length of data (44) */
u8 ap_address[ETH_ALEN];
u8 nonce[16];
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 r1kh_id[FT_R1KH_ID_LEN];
u8 s1kh_id[ETH_ALEN];
u8 pad[4]; /* 8-octet boundary for AES key wrap */
u8 key_wrap_extra[8];
} STRUCT_PACKED;
struct ft_r0kh_r1kh_resp_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
le16 data_length; /* little endian length of data (76) */
u8 ap_address[ETH_ALEN];
u8 nonce[16]; /* copied from pull */
u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
u8 s1kh_id[ETH_ALEN]; /* copied from pull */
u8 pmk_r1[PMK_LEN];
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
le16 pairwise;
u8 pad[2]; /* 8-octet boundary for AES key wrap */
u8 key_wrap_extra[8];
} STRUCT_PACKED;
struct ft_r0kh_r1kh_push_frame {
u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
le16 data_length; /* little endian length of data (88) */
u8 ap_address[ETH_ALEN];
/* Encrypted with AES key-wrap */
u8 timestamp[4]; /* current time in seconds since unix epoch, little
* endian */
u8 r1kh_id[FT_R1KH_ID_LEN];
u8 s1kh_id[ETH_ALEN];
u8 pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
le16 pairwise;
u8 pad[6]; /* 8-octet boundary for AES key wrap */
u8 key_wrap_extra[8];
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
/* per STA state machine data */
struct wpa_authenticator;
struct wpa_state_machine;
struct rsn_pmksa_cache_entry;
struct eapol_state_machine;
struct ft_remote_r0kh {
struct ft_remote_r0kh *next;
u8 addr[ETH_ALEN];
u8 id[FT_R0KH_ID_MAX_LEN];
size_t id_len;
u8 key[16];
};
struct ft_remote_r1kh {
struct ft_remote_r1kh *next;
u8 addr[ETH_ALEN];
u8 id[FT_R1KH_ID_LEN];
u8 key[16];
};
struct wpa_auth_config {
int wpa;
int wpa_key_mgmt;
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
int wpa_strict_rekey;
int wpa_gmk_rekey;
int wpa_ptk_rekey;
int rsn_pairwise;
int rsn_preauth;
int eapol_version;
int peerkey;
int wmm_enabled;
int wmm_uapsd;
int okc;
int tx_status;
#ifdef CONFIG_IEEE80211W
enum mfp_options ieee80211w;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
#define SSID_LEN 32
u8 ssid[SSID_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
size_t r0_key_holder_len;
u8 r1_key_holder[FT_R1KH_ID_LEN];
u32 r0_key_lifetime;
u32 reassociation_deadline;
struct ft_remote_r0kh *r0kh_list;
struct ft_remote_r1kh *r1kh_list;
int pmk_r1_push;
int ft_over_ds;
#endif /* CONFIG_IEEE80211R */
};
typedef enum {
LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
} logger_level;
typedef enum {
WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
} wpa_eapol_variable;
struct wpa_auth_callbacks {
void *ctx;
void (*logger)(void *ctx, const u8 *addr, logger_level level,
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
void (*mic_failure_report)(void *ctx, const u8 *addr);
void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
int value);
int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key, size_t key_len);
int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
size_t data_len, int encrypt);
int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
void *ctx), void *cb_ctx);
int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
void *ctx), void *cb_ctx);
int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
size_t data_len);
#ifdef CONFIG_IEEE80211R
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
#endif /* CONFIG_IEEE80211R */
};
struct wpa_authenticator * wpa_init(const u8 *addr,
struct wpa_auth_config *conf,
struct wpa_auth_callbacks *cb);
void wpa_deinit(struct wpa_authenticator *wpa_auth);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf);
enum {
WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
WPA_INVALID_MDIE, WPA_INVALID_PROTO
};
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len);
int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
struct wpa_state_machine *
wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm);
void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
void wpa_receive(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
u8 *data, size_t data_len);
typedef enum {
WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
WPA_REAUTH_EAPOL, WPA_ASSOC_FT
} wpa_event;
void wpa_remove_ptk(struct wpa_state_machine *sm);
int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
void wpa_auth_sm_notify(struct wpa_state_machine *sm);
void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
struct rsn_pmksa_cache_entry *entry);
struct rsn_pmksa_cache_entry *
wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
size_t *len);
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
int session_timeout, struct eapol_state_machine *eapol);
int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
const u8 *pmk, size_t len, const u8 *sta_addr,
int session_timeout,
struct eapol_state_machine *eapol);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);
#ifdef CONFIG_IEEE80211R
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
size_t max_len, int auth_alg,
const u8 *req_ies, size_t req_ies_len);
void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
u16 auth_transaction, const u8 *ies, size_t ies_len,
void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
u16 auth_transaction, u16 resp,
const u8 *ies, size_t ies_len),
void *ctx);
u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
size_t ies_len);
int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
const u8 *data, size_t data_len);
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
#endif /* WPA_AUTH_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,571 @@
/*
* hostapd / WPA authenticator glue code
* Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
#include "l2_packet/l2_packet.h"
#include "drivers/driver.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "preauth_auth.h"
#include "sta_info.h"
#include "tkip_countermeasures.h"
#include "ap_drv_ops.h"
#include "ap_config.h"
#include "wpa_auth.h"
static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
struct wpa_auth_config *wconf)
{
wconf->wpa = conf->wpa;
wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
wconf->wpa_pairwise = conf->wpa_pairwise;
wconf->wpa_group = conf->wpa_group;
wconf->wpa_group_rekey = conf->wpa_group_rekey;
wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
wconf->rsn_pairwise = conf->rsn_pairwise;
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
wconf->peerkey = conf->peerkey;
wconf->wmm_enabled = conf->wmm_enabled;
wconf->wmm_uapsd = conf->wmm_uapsd;
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_LEN)
wconf->ssid_len = SSID_LEN;
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN);
if (conf->nas_identifier &&
os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) {
wconf->r0_key_holder_len = os_strlen(conf->nas_identifier);
os_memcpy(wconf->r0_key_holder, conf->nas_identifier,
wconf->r0_key_holder_len);
}
os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
wconf->r0_key_lifetime = conf->r0_key_lifetime;
wconf->reassociation_deadline = conf->reassociation_deadline;
wconf->r0kh_list = conf->r0kh_list;
wconf->r1kh_list = conf->r1kh_list;
wconf->pmk_r1_push = conf->pmk_r1_push;
wconf->ft_over_ds = conf->ft_over_ds;
#endif /* CONFIG_IEEE80211R */
}
static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
logger_level level, const char *txt)
{
#ifndef CONFIG_NO_HOSTAPD_LOGGER
struct hostapd_data *hapd = ctx;
int hlevel;
switch (level) {
case LOGGER_WARNING:
hlevel = HOSTAPD_LEVEL_WARNING;
break;
case LOGGER_INFO:
hlevel = HOSTAPD_LEVEL_INFO;
break;
case LOGGER_DEBUG:
default:
hlevel = HOSTAPD_LEVEL_DEBUG;
break;
}
hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
#endif /* CONFIG_NO_HOSTAPD_LOGGER */
}
static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
u16 reason)
{
struct hostapd_data *hapd = ctx;
wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
"STA " MACSTR " reason %d",
__func__, MAC2STR(addr), reason);
ap_sta_disconnect(hapd, NULL, addr, reason);
}
static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
michael_mic_failure(hapd, addr, 0);
}
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
wpa_eapol_variable var, int value)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta == NULL)
return;
switch (var) {
case WPA_EAPOL_portEnabled:
ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
break;
case WPA_EAPOL_portValid:
ieee802_1x_notify_port_valid(sta->eapol_sm, value);
break;
case WPA_EAPOL_authorized:
ieee802_1x_set_sta_authorized(hapd, sta, value);
break;
case WPA_EAPOL_portControl_Auto:
if (sta->eapol_sm)
sta->eapol_sm->portControl = Auto;
break;
case WPA_EAPOL_keyRun:
if (sta->eapol_sm)
sta->eapol_sm->keyRun = value ? TRUE : FALSE;
break;
case WPA_EAPOL_keyAvailable:
if (sta->eapol_sm)
sta->eapol_sm->eap_if->eapKeyAvailable =
value ? TRUE : FALSE;
break;
case WPA_EAPOL_keyDone:
if (sta->eapol_sm)
sta->eapol_sm->keyDone = value ? TRUE : FALSE;
break;
case WPA_EAPOL_inc_EapolFramesTx:
if (sta->eapol_sm)
sta->eapol_sm->dot1xAuthEapolFramesTx++;
break;
}
}
static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
wpa_eapol_variable var)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta == NULL || sta->eapol_sm == NULL)
return -1;
switch (var) {
case WPA_EAPOL_keyRun:
return sta->eapol_sm->keyRun;
case WPA_EAPOL_keyAvailable:
return sta->eapol_sm->eap_if->eapKeyAvailable;
default:
return -1;
}
}
static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
const u8 *prev_psk)
{
struct hostapd_data *hapd = ctx;
return hostapd_get_psk(hapd->conf, addr, prev_psk);
}
static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
size_t *len)
{
struct hostapd_data *hapd = ctx;
const u8 *key;
size_t keylen;
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
if (sta == NULL)
return -1;
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
if (key == NULL)
return -1;
if (keylen > *len)
keylen = *len;
os_memcpy(msk, key, keylen);
*len = keylen;
return 0;
}
static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
const u8 *addr, int idx, u8 *key,
size_t key_len)
{
struct hostapd_data *hapd = ctx;
const char *ifname = hapd->conf->iface;
if (vlan_id > 0) {
ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
if (ifname == NULL)
return -1;
}
return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
key, key_len);
}
static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
u8 *seq)
{
struct hostapd_data *hapd = ctx;
return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
}
static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
const u8 *data, size_t data_len,
int encrypt)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
u32 flags = 0;
sta = ap_get_sta(hapd, addr);
if (sta)
flags = hostapd_sta_flags_to_drv(sta->flags);
return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
encrypt, flags);
}
static int hostapd_wpa_auth_for_each_sta(
void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
return 1;
}
return 0;
}
struct wpa_auth_iface_iter_data {
int (*cb)(struct wpa_authenticator *sm, void *ctx);
void *cb_ctx;
};
static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx)
{
struct wpa_auth_iface_iter_data *data = ctx;
size_t i;
for (i = 0; i < iface->num_bss; i++) {
if (iface->bss[i]->wpa_auth &&
data->cb(iface->bss[i]->wpa_auth, data->cb_ctx))
return 1;
}
return 0;
}
static int hostapd_wpa_auth_for_each_auth(
void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx),
void *cb_ctx)
{
struct hostapd_data *hapd = ctx;
struct wpa_auth_iface_iter_data data;
if (hapd->iface->for_each_interface == NULL)
return -1;
data.cb = cb;
data.cb_ctx = cb_ctx;
return hapd->iface->for_each_interface(hapd->iface->interfaces,
wpa_auth_iface_iter, &data);
}
#ifdef CONFIG_IEEE80211R
struct wpa_auth_ft_iface_iter_data {
struct hostapd_data *src_hapd;
const u8 *dst;
const u8 *data;
size_t data_len;
};
static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
{
struct wpa_auth_ft_iface_iter_data *idata = ctx;
struct hostapd_data *hapd;
size_t j;
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
if (hapd == idata->src_hapd)
continue;
if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
"locally managed BSS " MACSTR "@%s -> "
MACSTR "@%s",
MAC2STR(idata->src_hapd->own_addr),
idata->src_hapd->conf->iface,
MAC2STR(hapd->own_addr), hapd->conf->iface);
wpa_ft_rrb_rx(hapd->wpa_auth,
idata->src_hapd->own_addr,
idata->data, idata->data_len);
return 1;
}
}
return 0;
}
#endif /* CONFIG_IEEE80211R */
static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
const u8 *data, size_t data_len)
{
struct hostapd_data *hapd = ctx;
struct l2_ethhdr *buf;
int ret;
#ifdef CONFIG_IEEE80211R
if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
int res;
struct wpa_auth_ft_iface_iter_data idata;
idata.src_hapd = hapd;
idata.dst = dst;
idata.data = data;
idata.data_len = data_len;
res = hapd->iface->for_each_interface(hapd->iface->interfaces,
hostapd_wpa_auth_ft_iter,
&idata);
if (res == 1)
return data_len;
}
#endif /* CONFIG_IEEE80211R */
if (hapd->driver && hapd->driver->send_ether)
return hapd->driver->send_ether(hapd->drv_priv, dst,
hapd->own_addr, proto,
data, data_len);
if (hapd->l2 == NULL)
return -1;
buf = os_malloc(sizeof(*buf) + data_len);
if (buf == NULL)
return -1;
os_memcpy(buf->h_dest, dst, ETH_ALEN);
os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN);
buf->h_proto = host_to_be16(proto);
os_memcpy(buf + 1, data, data_len);
ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
sizeof(*buf) + data_len);
os_free(buf);
return ret;
}
#ifdef CONFIG_IEEE80211R
static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
const u8 *data, size_t data_len)
{
struct hostapd_data *hapd = ctx;
int res;
struct ieee80211_mgmt *m;
size_t mlen;
struct sta_info *sta;
sta = ap_get_sta(hapd, dst);
if (sta == NULL || sta->wpa_sm == NULL)
return -1;
m = os_zalloc(sizeof(*m) + data_len);
if (m == NULL)
return -1;
mlen = ((u8 *) &m->u - (u8 *) m) + data_len;
m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
os_memcpy(m->da, dst, ETH_ALEN);
os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
os_memcpy(&m->u, data, data_len);
res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen);
os_free(m);
return res;
}
static struct wpa_state_machine *
hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
return sta->wpa_sm;
}
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
if (sta->wpa_sm == NULL) {
ap_free_sta(hapd, sta);
return NULL;
}
sta->auth_alg = WLAN_AUTH_FT;
return sta->wpa_sm;
}
static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
struct hostapd_data *hapd = ctx;
struct l2_ethhdr *ethhdr;
if (len < sizeof(*ethhdr))
return;
ethhdr = (struct l2_ethhdr *) buf;
wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
len - sizeof(*ethhdr));
}
#endif /* CONFIG_IEEE80211R */
int hostapd_setup_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config _conf;
struct wpa_auth_callbacks cb;
const u8 *wpa_ie;
size_t wpa_ie_len;
hostapd_wpa_auth_conf(hapd->conf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = hapd;
cb.logger = hostapd_wpa_auth_logger;
cb.disconnect = hostapd_wpa_auth_disconnect;
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
cb.set_eapol = hostapd_wpa_auth_set_eapol;
cb.get_eapol = hostapd_wpa_auth_get_eapol;
cb.get_psk = hostapd_wpa_auth_get_psk;
cb.get_msk = hostapd_wpa_auth_get_msk;
cb.set_key = hostapd_wpa_auth_set_key;
cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
cb.send_eapol = hostapd_wpa_auth_send_eapol;
cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
cb.send_ether = hostapd_wpa_auth_send_ether;
#ifdef CONFIG_IEEE80211R
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
cb.add_sta = hostapd_wpa_auth_add_sta;
#endif /* CONFIG_IEEE80211R */
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
if (hapd->wpa_auth == NULL) {
wpa_printf(MSG_ERROR, "WPA initialization failed.");
return -1;
}
if (hostapd_set_privacy(hapd, 1)) {
wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
"for interface %s", hapd->conf->iface);
return -1;
}
wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
"the kernel driver.");
return -1;
}
if (rsn_preauth_iface_init(hapd)) {
wpa_printf(MSG_ERROR, "Initialization of RSN "
"pre-authentication failed.");
return -1;
}
#ifdef CONFIG_IEEE80211R
if (!hostapd_drv_none(hapd)) {
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
hapd->conf->bridge :
hapd->conf->iface, NULL, ETH_P_RRB,
hostapd_rrb_receive, hapd, 1);
if (hapd->l2 == NULL &&
(hapd->driver == NULL ||
hapd->driver->send_ether == NULL)) {
wpa_printf(MSG_ERROR, "Failed to open l2_packet "
"interface");
return -1;
}
}
#endif /* CONFIG_IEEE80211R */
return 0;
}
void hostapd_reconfig_wpa(struct hostapd_data *hapd)
{
struct wpa_auth_config wpa_auth_conf;
hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
}
void hostapd_deinit_wpa(struct hostapd_data *hapd)
{
rsn_preauth_iface_deinit(hapd);
if (hapd->wpa_auth) {
wpa_deinit(hapd->wpa_auth);
hapd->wpa_auth = NULL;
if (hostapd_set_privacy(hapd, 0)) {
wpa_printf(MSG_DEBUG, "Could not disable "
"PrivacyInvoked for interface %s",
hapd->conf->iface);
}
if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
wpa_printf(MSG_DEBUG, "Could not remove generic "
"information element from interface %s",
hapd->conf->iface);
}
}
ieee802_1x_deinit(hapd);
#ifdef CONFIG_IEEE80211R
l2_packet_deinit(hapd->l2);
#endif /* CONFIG_IEEE80211R */
}

View file

@ -0,0 +1,22 @@
/*
* hostapd / WPA authenticator glue code
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_AUTH_GLUE_H
#define WPA_AUTH_GLUE_H
int hostapd_setup_wpa(struct hostapd_data *hapd);
void hostapd_reconfig_wpa(struct hostapd_data *hapd);
void hostapd_deinit_wpa(struct hostapd_data *hapd);
#endif /* WPA_AUTH_GLUE_H */

View file

@ -0,0 +1,234 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_AUTH_I_H
#define WPA_AUTH_I_H
/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
#define RSNA_MAX_EAPOL_RETRIES 4
struct wpa_group;
struct wpa_stsl_negotiation {
struct wpa_stsl_negotiation *next;
u8 initiator[ETH_ALEN];
u8 peer[ETH_ALEN];
};
struct wpa_state_machine {
struct wpa_authenticator *wpa_auth;
struct wpa_group *group;
u8 addr[ETH_ALEN];
enum {
WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
} wpa_ptk_state;
enum {
WPA_PTK_GROUP_IDLE = 0,
WPA_PTK_GROUP_REKEYNEGOTIATING,
WPA_PTK_GROUP_REKEYESTABLISHED,
WPA_PTK_GROUP_KEYERROR
} wpa_ptk_group_state;
Boolean Init;
Boolean DeauthenticationRequest;
Boolean AuthenticationRequest;
Boolean ReAuthenticationRequest;
Boolean Disconnect;
int TimeoutCtr;
int GTimeoutCtr;
Boolean TimeoutEvt;
Boolean EAPOLKeyReceived;
Boolean EAPOLKeyPairwise;
Boolean EAPOLKeyRequest;
Boolean MICVerified;
Boolean GUpdateStationKeys;
u8 ANonce[WPA_NONCE_LEN];
u8 SNonce[WPA_NONCE_LEN];
u8 PMK[PMK_LEN];
struct wpa_ptk PTK;
Boolean PTK_valid;
Boolean pairwise_set;
int keycount;
Boolean Pair;
struct {
u8 counter[WPA_REPLAY_COUNTER_LEN];
Boolean valid;
} key_replay[RSNA_MAX_EAPOL_RETRIES];
Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
Boolean PTKRequest; /* not in IEEE 802.11i state machine */
Boolean has_GTK;
Boolean PtkGroupInit; /* init request for PTK Group state machine */
u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
size_t last_rx_eapol_key_len;
unsigned int changed:1;
unsigned int in_step_loop:1;
unsigned int pending_deinit:1;
unsigned int started:1;
unsigned int mgmt_frame_prot:1;
#ifdef CONFIG_IEEE80211R
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
u8 *wpa_ie;
size_t wpa_ie_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
} wpa;
int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
struct rsn_pmksa_cache_entry *pmksa;
u32 dot11RSNAStatsTKIPLocalMICFailures;
u32 dot11RSNAStatsTKIPRemoteMICFailures;
#ifdef CONFIG_IEEE80211R
u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
size_t xxkey_len;
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
* Request */
u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
size_t r0kh_id_len;
u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
* message 2/4 */
u8 *assoc_resp_ftie;
#endif /* CONFIG_IEEE80211R */
int pending_1_of_4_timeout;
};
/* per group key state machine data */
struct wpa_group {
struct wpa_group *next;
int vlan_id;
Boolean GInit;
int GKeyDoneStations;
Boolean GTKReKey;
int GTK_len;
int GN, GM;
Boolean GTKAuthenticator;
u8 Counter[WPA_NONCE_LEN];
enum {
WPA_GROUP_GTK_INIT = 0,
WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
} wpa_group_state;
u8 GMK[WPA_GMK_LEN];
u8 GTK[2][WPA_GTK_MAX_LEN];
u8 GNonce[WPA_NONCE_LEN];
Boolean changed;
Boolean first_sta_seen;
Boolean reject_4way_hs_for_entropy;
#ifdef CONFIG_IEEE80211W
u8 IGTK[2][WPA_IGTK_LEN];
int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */
};
struct wpa_ft_pmk_cache;
/* per authenticator data */
struct wpa_authenticator {
struct wpa_group *group;
unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
u32 dot11RSNAAuthenticationSuiteSelected;
u32 dot11RSNAPairwiseCipherSelected;
u32 dot11RSNAGroupCipherSelected;
u8 dot11RSNAPMKIDUsed[PMKID_LEN];
u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */
u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */
u32 dot11RSNAGroupCipherRequested; /* FIX: update */
unsigned int dot11RSNATKIPCounterMeasuresInvoked;
unsigned int dot11RSNA4WayHandshakeFailures;
struct wpa_stsl_negotiation *stsl_negotiations;
struct wpa_auth_config conf;
struct wpa_auth_callbacks cb;
u8 *wpa_ie;
size_t wpa_ie_len;
u8 addr[ETH_ALEN];
struct rsn_pmksa_cache *pmksa;
struct wpa_ft_pmk_cache *ft_pmk_cache;
};
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *fmt, ...);
void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int key_info,
const u8 *key_rsc, const u8 *nonce,
const u8 *kde, size_t kde_len,
int keyidx, int encr, int force_version);
int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_state_machine *sm, void *ctx),
void *cb_ctx);
int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
int (*cb)(struct wpa_authenticator *a, void *ctx),
void *cb_ctx);
#ifdef CONFIG_PEERKEY
int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
struct wpa_stsl_negotiation *neg);
void wpa_smk_error(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, struct wpa_eapol_key *key);
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211R
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
size_t r0kh_id_len,
const u8 *anonce, const u8 *snonce,
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk, size_t ptk_len);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
#endif /* CONFIG_IEEE80211R */
#endif /* WPA_AUTH_I_H */

View file

@ -0,0 +1,824 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "utils/includes.h"
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "ap_config.h"
#include "ieee802_11.h"
#include "wpa_auth.h"
#include "pmksa_cache_auth.h"
#include "wpa_auth_ie.h"
#include "wpa_auth_i.h"
#ifdef CONFIG_RSN_TESTING
int rsn_testing = 0;
#endif /* CONFIG_RSN_TESTING */
static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
struct wpa_ie_hdr *hdr;
int num_suites;
u8 *pos, *count;
hdr = (struct wpa_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
if (conf->wpa_group == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
} else {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
pos += WPA_SELECTOR_LEN;
num_suites = 0;
count = pos;
pos += 2;
if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->wpa_pairwise);
return -1;
}
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
count = pos;
pos += 2;
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
pos += WPA_SELECTOR_LEN;
num_suites++;
}
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
conf->wpa_key_mgmt);
return -1;
}
WPA_PUT_LE16(count, num_suites);
/* WPA Capabilities; use defaults, so no need to include it */
hdr->len = (pos - buf) - 2;
return pos - buf;
}
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
int num_suites;
u8 *pos, *count;
u16 capab;
hdr = (struct rsn_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_RSN;
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
if (conf->wpa_group == WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
} else {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
pos += RSN_SELECTOR_LEN;
num_suites = 0;
count = pos;
pos += 2;
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->rsn_pairwise);
return -1;
}
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
count = pos;
pos += 2;
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#ifdef CONFIG_IEEE80211R
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
pos += RSN_SELECTOR_LEN;
num_suites++;
}
#endif /* CONFIG_RSN_TESTING */
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
conf->wpa_key_mgmt);
return -1;
}
WPA_PUT_LE16(count, num_suites);
/* RSN Capabilities */
capab = 0;
if (conf->rsn_preauth)
capab |= WPA_CAPABILITY_PREAUTH;
if (conf->peerkey)
capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
if (conf->wmm_enabled) {
/* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
capab |= WPA_CAPABILITY_MFPC;
if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
capab |= WPA_CAPABILITY_MFPR;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing)
capab |= BIT(8) | BIT(14) | BIT(15);
#endif /* CONFIG_RSN_TESTING */
WPA_PUT_LE16(pos, capab);
pos += 2;
if (pmkid) {
if (pos + 2 + PMKID_LEN > buf + len)
return -1;
/* PMKID Count */
WPA_PUT_LE16(pos, 1);
pos += 2;
os_memcpy(pos, pmkid, PMKID_LEN);
pos += PMKID_LEN;
}
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (pos + 2 + 4 > buf + len)
return -1;
if (pmkid == NULL) {
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
}
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
/*
* Fill in any defined fields and add extra data to the end of
* the element.
*/
int pmkid_count_set = pmkid != NULL;
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
pmkid_count_set = 1;
/* PMKID Count */
WPA_PUT_LE16(pos, 0);
pos += 2;
if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
/* Management Group Cipher Suite */
RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
pos += RSN_SELECTOR_LEN;
}
os_memset(pos, 0x12, 17);
pos += 17;
}
#endif /* CONFIG_RSN_TESTING */
hdr->len = (pos - buf) - 2;
return pos - buf;
}
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
{
u8 *pos, buf[128];
int res;
pos = buf;
if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
res = wpa_write_rsn_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos, NULL);
if (res < 0)
return res;
pos += res;
}
#ifdef CONFIG_IEEE80211R
if (wpa_auth->conf.wpa_key_mgmt &
(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
res = wpa_write_mdie(&wpa_auth->conf, pos,
buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
#endif /* CONFIG_IEEE80211R */
if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
res = wpa_write_wpa_ie(&wpa_auth->conf,
pos, buf + sizeof(buf) - pos);
if (res < 0)
return res;
pos += res;
}
os_free(wpa_auth->wpa_ie);
wpa_auth->wpa_ie = os_malloc(pos - buf);
if (wpa_auth->wpa_ie == NULL)
return -1;
os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
wpa_auth->wpa_ie_len = pos - buf;
return 0;
}
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len)
{
*pos++ = WLAN_EID_VENDOR_SPECIFIC;
*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
RSN_SELECTOR_PUT(pos, kde);
pos += RSN_SELECTOR_LEN;
os_memcpy(pos, data, data_len);
pos += data_len;
if (data2) {
os_memcpy(pos, data2, data2_len);
pos += data2_len;
}
return pos;
}
struct wpa_auth_okc_iter_data {
struct rsn_pmksa_cache_entry *pmksa;
const u8 *aa;
const u8 *spa;
const u8 *pmkid;
};
static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
{
struct wpa_auth_okc_iter_data *data = ctx;
data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
data->pmkid);
if (data->pmksa)
return 1;
return 0;
}
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *mdie, size_t mdie_len)
{
struct wpa_ie_data data;
int ciphers, key_mgmt, res, version;
u32 selector;
size_t i;
const u8 *pmkid = NULL;
if (wpa_auth == NULL || sm == NULL)
return WPA_NOT_ENABLED;
if (wpa_ie == NULL || wpa_ie_len < 1)
return WPA_INVALID_IE;
if (wpa_ie[0] == WLAN_EID_RSN)
version = WPA_PROTO_RSN;
else
version = WPA_PROTO_WPA;
if (!(wpa_auth->conf.wpa & version)) {
wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
version, MAC2STR(sm->addr));
return WPA_INVALID_PROTO;
}
if (version == WPA_PROTO_RSN) {
res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
#ifdef CONFIG_IEEE80211R
else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
selector = RSN_AUTH_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
selector = RSN_CIPHER_SUITE_CCMP;
if (data.pairwise_cipher & WPA_CIPHER_CCMP)
selector = RSN_CIPHER_SUITE_CCMP;
else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
selector = RSN_CIPHER_SUITE_TKIP;
else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
selector = RSN_CIPHER_SUITE_WEP104;
else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
selector = RSN_CIPHER_SUITE_WEP40;
else if (data.pairwise_cipher & WPA_CIPHER_NONE)
selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
selector = RSN_CIPHER_SUITE_CCMP;
if (data.group_cipher & WPA_CIPHER_CCMP)
selector = RSN_CIPHER_SUITE_CCMP;
else if (data.group_cipher & WPA_CIPHER_TKIP)
selector = RSN_CIPHER_SUITE_TKIP;
else if (data.group_cipher & WPA_CIPHER_WEP104)
selector = RSN_CIPHER_SUITE_WEP104;
else if (data.group_cipher & WPA_CIPHER_WEP40)
selector = RSN_CIPHER_SUITE_WEP40;
else if (data.group_cipher & WPA_CIPHER_NONE)
selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
} else {
res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
selector = WPA_CIPHER_SUITE_TKIP;
if (data.pairwise_cipher & WPA_CIPHER_CCMP)
selector = WPA_CIPHER_SUITE_CCMP;
else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
selector = WPA_CIPHER_SUITE_TKIP;
else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
selector = WPA_CIPHER_SUITE_WEP104;
else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
selector = WPA_CIPHER_SUITE_WEP40;
else if (data.pairwise_cipher & WPA_CIPHER_NONE)
selector = WPA_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
selector = WPA_CIPHER_SUITE_TKIP;
if (data.group_cipher & WPA_CIPHER_CCMP)
selector = WPA_CIPHER_SUITE_CCMP;
else if (data.group_cipher & WPA_CIPHER_TKIP)
selector = WPA_CIPHER_SUITE_TKIP;
else if (data.group_cipher & WPA_CIPHER_WEP104)
selector = WPA_CIPHER_SUITE_WEP104;
else if (data.group_cipher & WPA_CIPHER_WEP40)
selector = WPA_CIPHER_SUITE_WEP40;
else if (data.group_cipher & WPA_CIPHER_NONE)
selector = WPA_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
}
if (res) {
wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
MACSTR " (res=%d)", MAC2STR(sm->addr), res);
wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
return WPA_INVALID_IE;
}
if (data.group_cipher != wpa_auth->conf.wpa_group) {
wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
MACSTR, data.group_cipher, MAC2STR(sm->addr));
return WPA_INVALID_GROUP;
}
key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
if (!key_mgmt) {
wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
MACSTR, data.key_mgmt, MAC2STR(sm->addr));
return WPA_INVALID_AKMP;
}
if (0) {
}
#ifdef CONFIG_IEEE80211R
else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
else
sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
if (version == WPA_PROTO_RSN)
ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
else
ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
if (!ciphers) {
wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
"from " MACSTR,
version == WPA_PROTO_RSN ? "RSN" : "WPA",
data.pairwise_cipher, MAC2STR(sm->addr));
return WPA_INVALID_PAIRWISE;
}
#ifdef CONFIG_IEEE80211W
if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
wpa_printf(MSG_DEBUG, "Management frame protection "
"required, but client did not enable it");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
if (ciphers & WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG, "Management frame protection "
"cannot use TKIP");
return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
}
if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "Unsupported management group "
"cipher %d", data.mgmt_group_cipher);
return WPA_INVALID_MGMT_GROUP_CIPHER;
}
}
if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
!(data.capabilities & WPA_CAPABILITY_MFPC))
sm->mgmt_frame_prot = 0;
else
sm->mgmt_frame_prot = 1;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
"MDIE not included");
return WPA_INVALID_MDIE;
}
if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
MOBILITY_DOMAIN_ID_LEN) != 0) {
wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
"MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
return WPA_INVALID_MDIE;
}
}
#endif /* CONFIG_IEEE80211R */
if (ciphers & WPA_CIPHER_CCMP)
sm->pairwise = WPA_CIPHER_CCMP;
else
sm->pairwise = WPA_CIPHER_TKIP;
/* TODO: clear WPA/WPA2 state if STA changes from one to another */
if (wpa_ie[0] == WLAN_EID_RSN)
sm->wpa = WPA_VERSION_WPA2;
else
sm->wpa = WPA_VERSION_WPA;
sm->pmksa = NULL;
for (i = 0; i < data.num_pmkid; i++) {
wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
&data.pmkid[i * PMKID_LEN], PMKID_LEN);
sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
&data.pmkid[i * PMKID_LEN]);
if (sm->pmksa) {
pmkid = sm->pmksa->pmkid;
break;
}
}
for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
i < data.num_pmkid; i++) {
struct wpa_auth_okc_iter_data idata;
idata.pmksa = NULL;
idata.aa = wpa_auth->addr;
idata.spa = sm->addr;
idata.pmkid = &data.pmkid[i * PMKID_LEN];
wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
if (idata.pmksa) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"OKC match for PMKID");
sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
idata.pmksa,
wpa_auth->addr,
idata.pmkid);
pmkid = idata.pmkid;
break;
}
}
if (sm->pmksa) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PMKID found from PMKSA cache "
"eap_type=%d vlan_id=%d",
sm->pmksa->eap_type_authsrv,
sm->pmksa->vlan_id);
os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
}
if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
os_free(sm->wpa_ie);
sm->wpa_ie = os_malloc(wpa_ie_len);
if (sm->wpa_ie == NULL)
return WPA_ALLOC_FAIL;
}
os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
sm->wpa_ie_len = wpa_ie_len;
return WPA_IE_OK;
}
/**
* wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
* @pos: Pointer to the IE header
* @end: Pointer to the end of the Key Data buffer
* @ie: Pointer to parsed IE data
* Returns: 0 on success, 1 if end mark is found, -1 on failure
*/
static int wpa_parse_generic(const u8 *pos, const u8 *end,
struct wpa_eapol_ie_parse *ie)
{
if (pos[1] == 0)
return 1;
if (pos[1] >= 6 &&
RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
pos[2 + WPA_SELECTOR_LEN] == 1 &&
pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
ie->wpa_ie = pos;
ie->wpa_ie_len = pos[1] + 2;
return 0;
}
if (pos + 1 + RSN_SELECTOR_LEN < end &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
#ifdef CONFIG_PEERKEY
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
ie->smk = pos + 2 + RSN_SELECTOR_LEN;
ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
ie->error = pos + 2 + RSN_SELECTOR_LEN;
ie->error_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
return 0;
}
#endif /* CONFIG_IEEE80211W */
return 0;
}
/**
* wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
* @buf: Pointer to the Key Data buffer
* @len: Key Data Length
* @ie: Pointer to parsed IE data
* Returns: 0 on success, -1 on failure
*/
int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
{
const u8 *pos, *end;
int ret = 0;
os_memset(ie, 0, sizeof(*ie));
for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
if (pos[0] == 0xdd &&
((pos == buf + len - 1) || pos[1] == 0)) {
/* Ignore padding */
break;
}
if (pos + 2 + pos[1] > end) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
"underflow (ie=%d len=%d pos=%d)",
pos[0], pos[1], (int) (pos - buf));
wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
buf, len);
ret = -1;
break;
}
if (*pos == WLAN_EID_RSN) {
ie->rsn_ie = pos;
ie->rsn_ie_len = pos[1] + 2;
#ifdef CONFIG_IEEE80211R
} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
ie->mdie = pos;
ie->mdie_len = pos[1] + 2;
} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
ie->ftie = pos;
ie->ftie_len = pos[1] + 2;
#endif /* CONFIG_IEEE80211R */
} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
ret = wpa_parse_generic(pos, end, ie);
if (ret < 0)
break;
if (ret > 0) {
ret = 0;
break;
}
} else {
wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
"Key Data IE", pos, 2 + pos[1]);
}
}
return ret;
}
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
}

View file

@ -0,0 +1,56 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_AUTH_IE_H
#define WPA_AUTH_IE_H
struct wpa_eapol_ie_parse {
const u8 *wpa_ie;
size_t wpa_ie_len;
const u8 *rsn_ie;
size_t rsn_ie_len;
const u8 *pmkid;
const u8 *gtk;
size_t gtk_len;
const u8 *mac_addr;
size_t mac_addr_len;
#ifdef CONFIG_PEERKEY
const u8 *smk;
size_t smk_len;
const u8 *nonce;
size_t nonce_len;
const u8 *lifetime;
size_t lifetime_len;
const u8 *error;
size_t error_len;
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
const u8 *igtk;
size_t igtk_len;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
const u8 *mdie;
size_t mdie_len;
const u8 *ftie;
size_t ftie_len;
#endif /* CONFIG_IEEE80211R */
};
int wpa_parse_kde_ies(const u8 *buf, size_t len,
struct wpa_eapol_ie_parse *ie);
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len);
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
#endif /* WPA_AUTH_IE_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,72 @@
/*
* hostapd / WPS integration
* Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPS_HOSTAPD_H
#define WPS_HOSTAPD_H
#ifdef CONFIG_WPS
int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf);
void hostapd_deinit_wps(struct hostapd_data *hapd);
void hostapd_update_wps(struct hostapd_data *hapd);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
const char *uuid, const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr);
int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
char *path, char *method, char *name);
int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
char *buf, size_t buflen);
void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
int timeout);
void hostapd_wps_update_ie(struct hostapd_data *hapd);
int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
const char *auth, const char *encr, const char *key);
#else /* CONFIG_WPS */
static inline int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf)
{
return 0;
}
static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
{
}
static inline void hostapd_update_wps(struct hostapd_data *hapd)
{
}
static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
const u8 *addr,
char *buf, size_t buflen)
{
return 0;
}
static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr)
{
return 0;
}
#endif /* CONFIG_WPS */
#endif /* WPS_HOSTAPD_H */

View file

@ -0,0 +1,8 @@
all:
@echo Nothing to be made.
clean:
rm -f *~ *.o *.d
install:
@echo Nothing to be made.

View file

@ -0,0 +1,270 @@
/*
* WPA Supplicant - Common definitions
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DEFS_H
#define DEFS_H
#ifdef FALSE
#undef FALSE
#endif
#ifdef TRUE
#undef TRUE
#endif
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
#define WPA_CIPHER_TKIP BIT(3)
#define WPA_CIPHER_CCMP BIT(4)
#ifdef CONFIG_IEEE80211W
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#endif /* CONFIG_IEEE80211W */
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
#define WPA_KEY_MGMT_NONE BIT(2)
#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
#define WPA_KEY_MGMT_WPA_NONE BIT(4)
#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
#define WPA_KEY_MGMT_FT_PSK BIT(6)
#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
#define WPA_KEY_MGMT_WPS BIT(9)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_FT_IEEE8021X |
WPA_KEY_MGMT_IEEE8021X_SHA256));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_PSK_SHA256));
}
static inline int wpa_key_mgmt_ft(int akm)
{
return !!(akm & (WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_FT_IEEE8021X));
}
static inline int wpa_key_mgmt_sha256(int akm)
{
return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
WPA_KEY_MGMT_IEEE8021X_SHA256));
}
static inline int wpa_key_mgmt_wpa(int akm)
{
return wpa_key_mgmt_wpa_ieee8021x(akm) ||
wpa_key_mgmt_wpa_psk(akm);
}
#define WPA_PROTO_WPA BIT(0)
#define WPA_PROTO_RSN BIT(1)
#define WPA_AUTH_ALG_OPEN BIT(0)
#define WPA_AUTH_ALG_SHARED BIT(1)
#define WPA_AUTH_ALG_LEAP BIT(2)
#define WPA_AUTH_ALG_FT BIT(3)
enum wpa_alg {
WPA_ALG_NONE,
WPA_ALG_WEP,
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
WPA_ALG_PMK
};
/**
* enum wpa_cipher - Cipher suites
*/
enum wpa_cipher {
CIPHER_NONE,
CIPHER_WEP40,
CIPHER_TKIP,
CIPHER_CCMP,
CIPHER_WEP104
};
/**
* enum wpa_key_mgmt - Key management suites
*/
enum wpa_key_mgmt {
KEY_MGMT_802_1X,
KEY_MGMT_PSK,
KEY_MGMT_NONE,
KEY_MGMT_802_1X_NO_WPA,
KEY_MGMT_WPA_NONE,
KEY_MGMT_FT_802_1X,
KEY_MGMT_FT_PSK,
KEY_MGMT_802_1X_SHA256,
KEY_MGMT_PSK_SHA256,
KEY_MGMT_WPS
};
/**
* enum wpa_states - wpa_supplicant state
*
* These enumeration values are used to indicate the current wpa_supplicant
* state (wpa_s->wpa_state). The current state can be retrieved with
* wpa_supplicant_get_state() function and the state can be changed by calling
* wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
* wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
* to access the state variable.
*/
enum wpa_states {
/**
* WPA_DISCONNECTED - Disconnected state
*
* This state indicates that client is not associated, but is likely to
* start looking for an access point. This state is entered when a
* connection is lost.
*/
WPA_DISCONNECTED,
/**
* WPA_INTERFACE_DISABLED - Interface disabled
*
* This stat eis entered if the network interface is disabled, e.g.,
* due to rfkill. wpa_supplicant refuses any new operations that would
* use the radio until the interface has been enabled.
*/
WPA_INTERFACE_DISABLED,
/**
* WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
*
* This state is entered if there are no enabled networks in the
* configuration. wpa_supplicant is not trying to associate with a new
* network and external interaction (e.g., ctrl_iface call to add or
* enable a network) is needed to start association.
*/
WPA_INACTIVE,
/**
* WPA_SCANNING - Scanning for a network
*
* This state is entered when wpa_supplicant starts scanning for a
* network.
*/
WPA_SCANNING,
/**
* WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to authenticate with and the driver is configured to try to
* authenticate with this BSS. This state is used only with drivers
* that use wpa_supplicant as the SME.
*/
WPA_AUTHENTICATING,
/**
* WPA_ASSOCIATING - Trying to associate with a BSS/SSID
*
* This state is entered when wpa_supplicant has found a suitable BSS
* to associate with and the driver is configured to try to associate
* with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
* state is entered when the driver is configured to try to associate
* with a network using the configured SSID and security policy.
*/
WPA_ASSOCIATING,
/**
* WPA_ASSOCIATED - Association completed
*
* This state is entered when the driver reports that association has
* been successfully completed with an AP. If IEEE 802.1X is used
* (with or without WPA/WPA2), wpa_supplicant remains in this state
* until the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_ASSOCIATED,
/**
* WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
*
* This state is entered when WPA/WPA2 4-Way Handshake is started. In
* case of WPA-PSK, this happens when receiving the first EAPOL-Key
* frame after association. In case of WPA-EAP, this state is entered
* when the IEEE 802.1X/EAPOL authentication has been completed.
*/
WPA_4WAY_HANDSHAKE,
/**
* WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
*
* This state is entered when 4-Way Key Handshake has been completed
* (i.e., when the supplicant sends out message 4/4) and when Group
* Key rekeying is started by the AP (i.e., when supplicant receives
* message 1/2).
*/
WPA_GROUP_HANDSHAKE,
/**
* WPA_COMPLETED - All authentication completed
*
* This state is entered when the full authentication process is
* completed. In case of WPA2, this happens when the 4-Way Handshake is
* successfully completed. With WPA, this state is entered after the
* Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
* completed after dynamic keys are received (or if not used, after
* the EAP authentication has been completed). With static WEP keys and
* plaintext connections, this state is entered when an association
* has been completed.
*
* This state indicates that the supplicant has completed its
* processing for the association phase and that data connection is
* fully configured.
*/
WPA_COMPLETED
};
#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
/**
* enum mfp_options - Management frame protection (IEEE 802.11w) options
*/
enum mfp_options {
NO_MGMT_FRAME_PROTECTION = 0,
MGMT_FRAME_PROTECTION_OPTIONAL = 1,
MGMT_FRAME_PROTECTION_REQUIRED = 2
};
/**
* enum hostapd_hw_mode - Hardware mode
*/
enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211B,
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
NUM_HOSTAPD_MODES
};
#endif /* DEFS_H */

View file

@ -0,0 +1,47 @@
/*
* EAPOL definitions shared between hostapd and wpa_supplicant
* Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef EAPOL_COMMON_H
#define EAPOL_COMMON_H
/* IEEE Std 802.1X-2004 */
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
struct ieee802_1x_hdr {
u8 version;
u8 type;
be16 length;
/* followed by length octets of data */
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
#define EAPOL_VERSION 2
enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
IEEE802_1X_TYPE_EAPOL_START = 1,
IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
IEEE802_1X_TYPE_EAPOL_KEY = 3,
IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
};
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
#endif /* EAPOL_COMMON_H */

View file

@ -0,0 +1,347 @@
/*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
struct ieee802_11_elems *elems,
int show_errors)
{
unsigned int oui;
/* first 3 bytes in vendor specific information element are the IEEE
* OUI of the vendor. The following byte is used a vendor specific
* sub-type. */
if (elen < 4) {
if (show_errors) {
wpa_printf(MSG_MSGDUMP, "short vendor specific "
"information element ignored (len=%lu)",
(unsigned long) elen);
}
return -1;
}
oui = WPA_GET_BE24(pos);
switch (oui) {
case OUI_MICROSOFT:
/* Microsoft/Wi-Fi information elements are further typed and
* subtyped */
switch (pos[3]) {
case 1:
/* Microsoft OUI (00:50:F2) with OUI Type 1:
* real WPA information element */
elems->wpa_ie = pos;
elems->wpa_ie_len = elen;
break;
case WMM_OUI_TYPE:
/* WMM information element */
if (elen < 5) {
wpa_printf(MSG_MSGDUMP, "short WMM "
"information element ignored "
"(len=%lu)",
(unsigned long) elen);
return -1;
}
switch (pos[4]) {
case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
/*
* Share same pointer since only one of these
* is used and they start with same data.
* Length field can be used to distinguish the
* IEs.
*/
elems->wmm = pos;
elems->wmm_len = elen;
break;
case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
elems->wmm_tspec = pos;
elems->wmm_tspec_len = elen;
break;
default:
wpa_printf(MSG_EXCESSIVE, "unknown WMM "
"information element ignored "
"(subtype=%d len=%lu)",
pos[4], (unsigned long) elen);
return -1;
}
break;
case 4:
/* Wi-Fi Protected Setup (WPS) IE */
elems->wps_ie = pos;
elems->wps_ie_len = elen;
break;
default:
wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
"information element ignored "
"(type=%d len=%lu)",
pos[3], (unsigned long) elen);
return -1;
}
break;
case OUI_WFA:
switch (pos[3]) {
case P2P_OUI_TYPE:
/* Wi-Fi Alliance - P2P IE */
elems->p2p = pos;
elems->p2p_len = elen;
break;
default:
wpa_printf(MSG_MSGDUMP, "Unknown WFA "
"information element ignored "
"(type=%d len=%lu)\n",
pos[3], (unsigned long) elen);
return -1;
}
break;
case OUI_BROADCOM:
switch (pos[3]) {
case VENDOR_HT_CAPAB_OUI_TYPE:
elems->vendor_ht_cap = pos;
elems->vendor_ht_cap_len = elen;
break;
default:
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
"information element ignored "
"(type=%d len=%lu)",
pos[3], (unsigned long) elen);
return -1;
}
break;
default:
wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
"information element ignored (vendor OUI "
"%02x:%02x:%02x len=%lu)",
pos[0], pos[1], pos[2], (unsigned long) elen);
return -1;
}
return 0;
}
/**
* ieee802_11_parse_elems - Parse information elements in management frames
* @start: Pointer to the start of IEs
* @len: Length of IE buffer in octets
* @elems: Data structure for parsed elements
* @show_errors: Whether to show parsing errors in debug log
* Returns: Parsing result
*/
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors)
{
size_t left = len;
const u8 *pos = start;
int unknown = 0;
os_memset(elems, 0, sizeof(*elems));
while (left >= 2) {
u8 id, elen;
id = *pos++;
elen = *pos++;
left -= 2;
if (elen > left) {
if (show_errors) {
wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
"parse failed (id=%d elen=%d "
"left=%lu)",
id, elen, (unsigned long) left);
wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
}
return ParseFailed;
}
switch (id) {
case WLAN_EID_SSID:
elems->ssid = pos;
elems->ssid_len = elen;
break;
case WLAN_EID_SUPP_RATES:
elems->supp_rates = pos;
elems->supp_rates_len = elen;
break;
case WLAN_EID_FH_PARAMS:
elems->fh_params = pos;
elems->fh_params_len = elen;
break;
case WLAN_EID_DS_PARAMS:
elems->ds_params = pos;
elems->ds_params_len = elen;
break;
case WLAN_EID_CF_PARAMS:
elems->cf_params = pos;
elems->cf_params_len = elen;
break;
case WLAN_EID_TIM:
elems->tim = pos;
elems->tim_len = elen;
break;
case WLAN_EID_IBSS_PARAMS:
elems->ibss_params = pos;
elems->ibss_params_len = elen;
break;
case WLAN_EID_CHALLENGE:
elems->challenge = pos;
elems->challenge_len = elen;
break;
case WLAN_EID_ERP_INFO:
elems->erp_info = pos;
elems->erp_info_len = elen;
break;
case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
elems->ext_supp_rates_len = elen;
break;
case WLAN_EID_VENDOR_SPECIFIC:
if (ieee802_11_parse_vendor_specific(pos, elen,
elems,
show_errors))
unknown++;
break;
case WLAN_EID_RSN:
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
case WLAN_EID_PWR_CAPABILITY:
elems->power_cap = pos;
elems->power_cap_len = elen;
break;
case WLAN_EID_SUPPORTED_CHANNELS:
elems->supp_channels = pos;
elems->supp_channels_len = elen;
break;
case WLAN_EID_MOBILITY_DOMAIN:
elems->mdie = pos;
elems->mdie_len = elen;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
elems->ftie = pos;
elems->ftie_len = elen;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
elems->timeout_int = pos;
elems->timeout_int_len = elen;
break;
case WLAN_EID_HT_CAP:
elems->ht_capabilities = pos;
elems->ht_capabilities_len = elen;
break;
case WLAN_EID_HT_OPERATION:
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
elems->link_id = pos;
break;
default:
unknown++;
if (!show_errors)
break;
wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
"ignored unknown element (id=%d elen=%d)",
id, elen);
break;
}
left -= elen;
pos += elen;
}
if (left)
return ParseFailed;
return unknown ? ParseUnknown : ParseOK;
}
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
int count = 0;
const u8 *pos, *end;
if (ies == NULL)
return 0;
pos = ies;
end = ies + ies_len;
while (pos + 2 <= end) {
if (pos + 2 + pos[1] > end)
break;
count++;
pos += 2 + pos[1];
}
return count;
}
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type)
{
struct wpabuf *buf;
const u8 *end, *pos, *ie;
pos = ies;
end = ies + ies_len;
ie = NULL;
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
return NULL;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
WPA_GET_BE32(&pos[2]) == oui_type) {
ie = pos;
break;
}
pos += 2 + pos[1];
}
if (ie == NULL)
return NULL; /* No specified vendor IE found */
buf = wpabuf_alloc(ies_len);
if (buf == NULL)
return NULL;
/*
* There may be multiple vendor IEs in the message, so need to
* concatenate their data fields.
*/
while (pos + 1 < end) {
if (pos + 2 + pos[1] > end)
break;
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
WPA_GET_BE32(&pos[2]) == oui_type)
wpabuf_put_data(buf, pos + 6, pos[1] - 4);
pos += 2 + pos[1];
}
return buf;
}

View file

@ -0,0 +1,81 @@
/*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_11_COMMON_H
#define IEEE802_11_COMMON_H
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
const u8 *supp_rates;
const u8 *fh_params;
const u8 *ds_params;
const u8 *cf_params;
const u8 *tim;
const u8 *ibss_params;
const u8 *challenge;
const u8 *erp_info;
const u8 *ext_supp_rates;
const u8 *wpa_ie;
const u8 *rsn_ie;
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
const u8 *power_cap;
const u8 *supp_channels;
const u8 *mdie;
const u8 *ftie;
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
const u8 *vendor_ht_cap;
const u8 *p2p;
const u8 *link_id;
u8 ssid_len;
u8 supp_rates_len;
u8 fh_params_len;
u8 ds_params_len;
u8 cf_params_len;
u8 tim_len;
u8 ibss_params_len;
u8 challenge_len;
u8 erp_info_len;
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
u8 power_cap_len;
u8 supp_channels_len;
u8 mdie_len;
u8 ftie_len;
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
u8 vendor_ht_cap_len;
u8 p2p_len;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
struct ieee802_11_elems *elems,
int show_errors);
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type);
#endif /* IEEE802_11_COMMON_H */

View file

@ -0,0 +1,800 @@
/*
* IEEE 802.11 Frame type definitions
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef IEEE802_11_DEFS_H
#define IEEE802_11_DEFS_H
/* IEEE 802.11 defines */
#define WLAN_FC_PVER 0x0003
#define WLAN_FC_TODS 0x0100
#define WLAN_FC_FROMDS 0x0200
#define WLAN_FC_MOREFRAG 0x0400
#define WLAN_FC_RETRY 0x0800
#define WLAN_FC_PWRMGT 0x1000
#define WLAN_FC_MOREDATA 0x2000
#define WLAN_FC_ISWEP 0x4000
#define WLAN_FC_ORDER 0x8000
#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
#define WLAN_GET_SEQ_SEQ(seq) \
(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
#define WLAN_FC_TYPE_MGMT 0
#define WLAN_FC_TYPE_CTRL 1
#define WLAN_FC_TYPE_DATA 2
/* management */
#define WLAN_FC_STYPE_ASSOC_REQ 0
#define WLAN_FC_STYPE_ASSOC_RESP 1
#define WLAN_FC_STYPE_REASSOC_REQ 2
#define WLAN_FC_STYPE_REASSOC_RESP 3
#define WLAN_FC_STYPE_PROBE_REQ 4
#define WLAN_FC_STYPE_PROBE_RESP 5
#define WLAN_FC_STYPE_BEACON 8
#define WLAN_FC_STYPE_ATIM 9
#define WLAN_FC_STYPE_DISASSOC 10
#define WLAN_FC_STYPE_AUTH 11
#define WLAN_FC_STYPE_DEAUTH 12
#define WLAN_FC_STYPE_ACTION 13
/* control */
#define WLAN_FC_STYPE_PSPOLL 10
#define WLAN_FC_STYPE_RTS 11
#define WLAN_FC_STYPE_CTS 12
#define WLAN_FC_STYPE_ACK 13
#define WLAN_FC_STYPE_CFEND 14
#define WLAN_FC_STYPE_CFENDACK 15
/* data */
#define WLAN_FC_STYPE_DATA 0
#define WLAN_FC_STYPE_DATA_CFACK 1
#define WLAN_FC_STYPE_DATA_CFPOLL 2
#define WLAN_FC_STYPE_DATA_CFACKPOLL 3
#define WLAN_FC_STYPE_NULLFUNC 4
#define WLAN_FC_STYPE_CFACK 5
#define WLAN_FC_STYPE_CFPOLL 6
#define WLAN_FC_STYPE_CFACKPOLL 7
#define WLAN_FC_STYPE_QOS_DATA 8
#define WLAN_FC_STYPE_QOS_DATA_CFACK 9
#define WLAN_FC_STYPE_QOS_DATA_CFPOLL 10
#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL 11
#define WLAN_FC_STYPE_QOS_NULL 12
#define WLAN_FC_STYPE_QOS_CFPOLL 14
#define WLAN_FC_STYPE_QOS_CFACKPOLL 15
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
#define WLAN_AUTH_SHARED_KEY 1
#define WLAN_AUTH_FT 2
#define WLAN_AUTH_LEAP 128
#define WLAN_AUTH_CHALLENGE_LEN 128
#define WLAN_CAPABILITY_ESS BIT(0)
#define WLAN_CAPABILITY_IBSS BIT(1)
#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
#define WLAN_CAPABILITY_PRIVACY BIT(4)
#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
#define WLAN_CAPABILITY_PBCC BIT(6)
#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
#define WLAN_STATUS_SUCCESS 0
#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
#define WLAN_STATUS_SECURITY_DISABLED 5
#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
#define WLAN_STATUS_NOT_IN_SAME_BSS 7
#define WLAN_STATUS_CAPS_UNSUPPORTED 10
#define WLAN_STATUS_REASSOC_NO_ASSOC 11
#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
#define WLAN_STATUS_CHALLENGE_FAIL 15
#define WLAN_STATUS_AUTH_TIMEOUT 16
#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
#define WLAN_STATUS_ASSOC_DENIED_RATES 18
/* IEEE 802.11b */
#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
/* IEEE 802.11h */
#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
/* IEEE 802.11g */
#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
#define WLAN_STATUS_R0KH_UNREACHABLE 28
#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
/* IEEE 802.11w */
#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
#define WLAN_STATUS_REQUEST_DECLINED 37
#define WLAN_STATUS_INVALID_PARAMETERS 38
/* IEEE 802.11i */
#define WLAN_STATUS_INVALID_IE 40
#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
#define WLAN_STATUS_AKMP_NOT_VALID 43
#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
#define WLAN_STATUS_TS_NOT_CREATED 47
#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
/* IEEE 802.11r */
#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
#define WLAN_STATUS_INVALID_PMKID 53
#define WLAN_STATUS_INVALID_MDIE 54
#define WLAN_STATUS_INVALID_FTIE 55
#define WLAN_STATUS_INVALID_RSNIE 72
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
#define WLAN_REASON_DEAUTH_LEAVING 3
#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
#define WLAN_REASON_DISASSOC_AP_BUSY 5
#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
/* IEEE 802.11h */
#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
/* IEEE 802.11i */
#define WLAN_REASON_INVALID_IE 13
#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
#define WLAN_REASON_AKMP_NOT_VALID 20
#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
/* IEEE 802.11e */
#define WLAN_REASON_DISASSOC_LOW_ACK 34
/* Information Element IDs */
#define WLAN_EID_SSID 0
#define WLAN_EID_SUPP_RATES 1
#define WLAN_EID_FH_PARAMS 2
#define WLAN_EID_DS_PARAMS 3
#define WLAN_EID_CF_PARAMS 4
#define WLAN_EID_TIM 5
#define WLAN_EID_IBSS_PARAMS 6
#define WLAN_EID_COUNTRY 7
#define WLAN_EID_CHALLENGE 16
/* EIDs defined by IEEE 802.11h - START */
#define WLAN_EID_PWR_CONSTRAINT 32
#define WLAN_EID_PWR_CAPABILITY 33
#define WLAN_EID_TPC_REQUEST 34
#define WLAN_EID_TPC_REPORT 35
#define WLAN_EID_SUPPORTED_CHANNELS 36
#define WLAN_EID_CHANNEL_SWITCH 37
#define WLAN_EID_MEASURE_REQUEST 38
#define WLAN_EID_MEASURE_REPORT 39
#define WLAN_EID_QUITE 40
#define WLAN_EID_IBSS_DFS 41
/* EIDs defined by IEEE 802.11h - END */
#define WLAN_EID_ERP_INFO 42
#define WLAN_EID_HT_CAP 45
#define WLAN_EID_RSN 48
#define WLAN_EID_EXT_SUPP_RATES 50
#define WLAN_EID_MOBILITY_DOMAIN 54
#define WLAN_EID_FAST_BSS_TRANSITION 55
#define WLAN_EID_TIMEOUT_INTERVAL 56
#define WLAN_EID_RIC_DATA 57
#define WLAN_EID_HT_OPERATION 61
#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
#define WLAN_EID_20_40_BSS_COEXISTENCE 72
#define WLAN_EID_20_40_BSS_INTOLERANT 73
#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
#define WLAN_EID_MMIE 76
#define WLAN_EID_LINK_ID 101
#define WLAN_EID_ADV_PROTO 108
#define WLAN_EID_EXT_CAPAB 127
#define WLAN_EID_VENDOR_SPECIFIC 221
/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1
#define WLAN_ACTION_DLS 2
#define WLAN_ACTION_BLOCK_ACK 3
#define WLAN_ACTION_PUBLIC 4
#define WLAN_ACTION_RADIO_MEASUREMENT 5
#define WLAN_ACTION_FT 6
#define WLAN_ACTION_HT 7
#define WLAN_ACTION_SA_QUERY 8
#define WLAN_ACTION_TDLS 12
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Public action codes */
#define WLAN_PA_VENDOR_SPECIFIC 9
#define WLAN_PA_GAS_INITIAL_REQ 10
#define WLAN_PA_GAS_INITIAL_RESP 11
#define WLAN_PA_GAS_COMEBACK_REQ 12
#define WLAN_PA_GAS_COMEBACK_RESP 13
/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
#define WLAN_SA_QUERY_REQUEST 0
#define WLAN_SA_QUERY_RESPONSE 1
#define WLAN_SA_QUERY_TR_ID_LEN 2
/* TDLS action codes */
#define WLAN_TDLS_SETUP_REQUEST 0
#define WLAN_TDLS_SETUP_RESPONSE 1
#define WLAN_TDLS_SETUP_CONFIRM 2
#define WLAN_TDLS_TEARDOWN 3
#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
#define WLAN_TDLS_PEER_PSM_REQUEST 7
#define WLAN_TDLS_PEER_PSM_RESPONSE 8
#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
#define WLAN_TDLS_DISCOVERY_REQUEST 10
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
#define WLAN_TIMEOUT_KEY_LIFETIME 2
#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
/* Advertisement Protocol ID definitions (IEEE 802.11u) */
enum adv_proto_id {
NATIVE_QUERY_PROTOCOL = 0,
MIH_INFO_SERVICE = 1,
MIH_CMD_AND_EVENT_DISCOVERY = 2,
EMERGENCY_ALERT_SYSTEM = 3,
LOCATION_TO_SERVICE = 4,
ADV_PROTO_VENDOR_SPECIFIC = 221
};
/* Native Query Protocol info ID definitions (IEEE 802.11u) */
enum nqp_info_id {
NQP_CAPABILITY_LIST = 256,
NQP_VENUE_NAME = 257,
NQP_EMERGENCY_CALL_NUMBER = 258,
NQP_NETWORK_AUTH_TYPE = 259,
NQP_ROAMING_CONSORTIUM = 260,
NQP_IP_ADDR_TYPE_AVAILABILITY = 261,
NQP_NAI_REALM = 262,
NQP_3GPP_CELLULAR_NETWORK = 263,
NQP_AP_GEOSPATIAL_LOCATION = 264,
NQP_AP_CIVIC_LOCATION = 265,
NQP_DOMAIN_NAME = 266,
NQP_EMERGENCY_ALERT_URI = 267,
NQP_VENDOR_SPECIFIC = 56797
};
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
struct ieee80211_hdr {
le16 frame_control;
le16 duration_id;
u8 addr1[6];
u8 addr2[6];
u8 addr3[6];
le16 seq_ctrl;
/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
*/
} STRUCT_PACKED;
#define IEEE80211_DA_FROMDS addr1
#define IEEE80211_BSSID_FROMDS addr2
#define IEEE80211_SA_FROMDS addr3
#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
struct ieee80211_mgmt {
le16 frame_control;
le16 duration;
u8 da[6];
u8 sa[6];
u8 bssid[6];
le16 seq_ctrl;
union {
struct {
le16 auth_alg;
le16 auth_transaction;
le16 status_code;
/* possibly followed by Challenge text */
u8 variable[0];
} STRUCT_PACKED auth;
struct {
le16 reason_code;
u8 variable[0];
} STRUCT_PACKED deauth;
struct {
le16 capab_info;
le16 listen_interval;
/* followed by SSID and Supported rates */
u8 variable[0];
} STRUCT_PACKED assoc_req;
struct {
le16 capab_info;
le16 status_code;
le16 aid;
/* followed by Supported rates */
u8 variable[0];
} STRUCT_PACKED assoc_resp, reassoc_resp;
struct {
le16 capab_info;
le16 listen_interval;
u8 current_ap[6];
/* followed by SSID and Supported rates */
u8 variable[0];
} STRUCT_PACKED reassoc_req;
struct {
le16 reason_code;
u8 variable[0];
} STRUCT_PACKED disassoc;
struct {
u8 timestamp[8];
le16 beacon_int;
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[0];
} STRUCT_PACKED beacon;
struct {
/* only variable items: SSID, Supported rates */
u8 variable[0];
} STRUCT_PACKED probe_req;
struct {
u8 timestamp[8];
le16 beacon_int;
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params */
u8 variable[0];
} STRUCT_PACKED probe_resp;
struct {
u8 category;
union {
struct {
u8 action_code;
u8 dialog_token;
u8 status_code;
u8 variable[0];
} STRUCT_PACKED wmm_action;
struct{
u8 action_code;
u8 element_id;
u8 length;
u8 switch_mode;
u8 new_chan;
u8 switch_count;
} STRUCT_PACKED chan_switch;
struct {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
u8 variable[0]; /* FT Request */
} STRUCT_PACKED ft_action_req;
struct {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
le16 status_code;
u8 variable[0]; /* FT Request */
} STRUCT_PACKED ft_action_resp;
struct {
u8 action;
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
} STRUCT_PACKED sa_query_req;
struct {
u8 action; /* */
u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
} STRUCT_PACKED sa_query_resp;
struct {
u8 action;
u8 variable[0];
} STRUCT_PACKED public_action;
struct {
u8 action; /* 9 */
u8 oui[3];
/* Vendor-specific content */
u8 variable[0];
} STRUCT_PACKED vs_public_action;
} u;
} STRUCT_PACKED action;
} u;
} STRUCT_PACKED;
struct ieee80211_ht_capabilities {
le16 ht_capabilities_info;
u8 a_mpdu_params;
u8 supported_mcs_set[16];
le16 ht_extended_capabilities;
le32 tx_bf_capability_info;
u8 asel_capabilities;
} STRUCT_PACKED;
struct ieee80211_ht_operation {
u8 control_chan;
u8 ht_param;
le16 operation_mode;
le16 stbc_param;
u8 basic_set[16];
} STRUCT_PACKED;
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
#define ERP_INFO_NON_ERP_PRESENT BIT(0)
#define ERP_INFO_USE_PROTECTION BIT(1)
#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
#define HT_CAP_INFO_LDPC_CODING_CAP ((u16) BIT(0))
#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET ((u16) BIT(1))
#define HT_CAP_INFO_SMPS_MASK ((u16) (BIT(2) | BIT(3)))
#define HT_CAP_INFO_SMPS_STATIC ((u16) 0)
#define HT_CAP_INFO_SMPS_DYNAMIC ((u16) BIT(2))
#define HT_CAP_INFO_SMPS_DISABLED ((u16) (BIT(2) | BIT(3)))
#define HT_CAP_INFO_GREEN_FIELD ((u16) BIT(4))
#define HT_CAP_INFO_SHORT_GI20MHZ ((u16) BIT(5))
#define HT_CAP_INFO_SHORT_GI40MHZ ((u16) BIT(6))
#define HT_CAP_INFO_TX_STBC ((u16) BIT(7))
#define HT_CAP_INFO_RX_STBC_MASK ((u16) (BIT(8) | BIT(9)))
#define HT_CAP_INFO_RX_STBC_1 ((u16) BIT(8))
#define HT_CAP_INFO_RX_STBC_12 ((u16) BIT(9))
#define HT_CAP_INFO_RX_STBC_123 ((u16) (BIT(8) | BIT(9)))
#define HT_CAP_INFO_DELAYED_BA ((u16) BIT(10))
#define HT_CAP_INFO_MAX_AMSDU_SIZE ((u16) BIT(11))
#define HT_CAP_INFO_DSSS_CCK40MHZ ((u16) BIT(12))
#define HT_CAP_INFO_PSMP_SUPP ((u16) BIT(13))
#define HT_CAP_INFO_40MHZ_INTOLERANT ((u16) BIT(14))
#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT ((u16) BIT(15))
#define EXT_HT_CAP_INFO_PCO ((u16) BIT(0))
#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET 1
#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET 8
#define EXT_HT_CAP_INFO_HTC_SUPPORTED ((u16) BIT(10))
#define EXT_HT_CAP_INFO_RD_RESPONDER ((u16) BIT(11))
#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK ((u8) BIT(0) | BIT(1))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE ((u8) BIT(0))
#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW ((u8) BIT(0) | BIT(1))
#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH ((u8) BIT(2))
#define HT_INFO_HT_PARAM_RIFS_MODE ((u8) BIT(3))
#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY ((u8) BIT(4))
#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY ((u8) BIT(5))
#define OP_MODE_PURE 0
#define OP_MODE_MAY_BE_LEGACY_STAS 1
#define OP_MODE_20MHZ_HT_STA_ASSOCED 2
#define OP_MODE_MIXED 3
#define HT_INFO_OPERATION_MODE_OP_MODE_MASK \
((le16) (0x0001 | 0x0002))
#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET 0
#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT ((u8) BIT(2))
#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT ((u8) BIT(3))
#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT ((u8) BIT(4))
#define HT_INFO_STBC_PARAM_DUAL_BEACON ((u16) BIT(6))
#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT ((u16) BIT(7))
#define HT_INFO_STBC_PARAM_SECONDARY_BCN ((u16) BIT(8))
#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED ((u16) BIT(9))
#define HT_INFO_STBC_PARAM_PCO_ACTIVE ((u16) BIT(10))
#define HT_INFO_STBC_PARAM_PCO_PHASE ((u16) BIT(11))
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
#define WPA_IE_VENDOR_TYPE 0x0050f201
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
#define WMM_OUI_TYPE 2
#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
#define WMM_VERSION 1
#define WMM_ACTION_CODE_ADDTS_REQ 0
#define WMM_ACTION_CODE_ADDTS_RESP 1
#define WMM_ACTION_CODE_DELTS 2
#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
/* 2 - Reserved */
#define WMM_ADDTS_STATUS_REFUSED 3
/* 4-255 - Reserved */
/* WMM TSPEC Direction Field Values */
#define WMM_TSPEC_DIRECTION_UPLINK 0
#define WMM_TSPEC_DIRECTION_DOWNLINK 1
/* 2 - Reserved */
#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
/*
* WMM Information Element (used in (Re)Association Request frames; may also be
* used in Beacon frames)
*/
struct wmm_information_element {
/* Element ID: 221 (0xdd); Length: 7 */
/* required fields for WMM version 1 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 0 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specific QoS info */
} STRUCT_PACKED;
#define WMM_AC_AIFSN_MASK 0x0f
#define WMM_AC_AIFNS_SHIFT 0
#define WMM_AC_ACM 0x10
#define WMM_AC_ACI_MASK 0x60
#define WMM_AC_ACI_SHIFT 5
#define WMM_AC_ECWMIN_MASK 0x0f
#define WMM_AC_ECWMIN_SHIFT 0
#define WMM_AC_ECWMAX_MASK 0xf0
#define WMM_AC_ECWMAX_SHIFT 4
struct wmm_ac_parameter {
u8 aci_aifsn; /* AIFSN, ACM, ACI */
u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
le16 txop_limit;
} STRUCT_PACKED;
/*
* WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
* Response frmaes)
*/
struct wmm_parameter_element {
/* Element ID: 221 (0xdd); Length: 24 */
/* required fields for WMM version 1 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 1 */
u8 version; /* 1 for WMM version 1.0 */
u8 qos_info; /* AP/STA specif QoS info */
u8 reserved; /* 0 */
struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
} STRUCT_PACKED;
/* WMM TSPEC Element */
struct wmm_tspec_element {
u8 eid; /* 221 = 0xdd */
u8 length; /* 6 + 55 = 61 */
u8 oui[3]; /* 00:50:f2 */
u8 oui_type; /* 2 */
u8 oui_subtype; /* 2 */
u8 version; /* 1 */
/* WMM TSPEC body (55 octets): */
u8 ts_info[3];
le16 nominal_msdu_size;
le16 maximum_msdu_size;
le32 minimum_service_interval;
le32 maximum_service_interval;
le32 inactivity_interval;
le32 suspension_interval;
le32 service_start_time;
le32 minimum_data_rate;
le32 mean_data_rate;
le32 peak_data_rate;
le32 maximum_burst_size;
le32 delay_bound;
le32 minimum_phy_rate;
le16 surplus_bandwidth_allowance;
le16 medium_time;
} STRUCT_PACKED;
/* Access Categories / ACI to AC coding */
enum {
WMM_AC_BE = 0 /* Best Effort */,
WMM_AC_BK = 1 /* Background */,
WMM_AC_VI = 2 /* Video */,
WMM_AC_VO = 3 /* Voice */
};
/* Wi-Fi Direct (P2P) */
#define P2P_OUI_TYPE 9
enum p2p_attr_id {
P2P_ATTR_STATUS = 0,
P2P_ATTR_MINOR_REASON_CODE = 1,
P2P_ATTR_CAPABILITY = 2,
P2P_ATTR_DEVICE_ID = 3,
P2P_ATTR_GROUP_OWNER_INTENT = 4,
P2P_ATTR_CONFIGURATION_TIMEOUT = 5,
P2P_ATTR_LISTEN_CHANNEL = 6,
P2P_ATTR_GROUP_BSSID = 7,
P2P_ATTR_EXT_LISTEN_TIMING = 8,
P2P_ATTR_INTENDED_INTERFACE_ADDR = 9,
P2P_ATTR_MANAGEABILITY = 10,
P2P_ATTR_CHANNEL_LIST = 11,
P2P_ATTR_NOTICE_OF_ABSENCE = 12,
P2P_ATTR_DEVICE_INFO = 13,
P2P_ATTR_GROUP_INFO = 14,
P2P_ATTR_GROUP_ID = 15,
P2P_ATTR_INTERFACE = 16,
P2P_ATTR_OPERATING_CHANNEL = 17,
P2P_ATTR_INVITATION_FLAGS = 18,
P2P_ATTR_VENDOR_SPECIFIC = 221
};
#define P2P_MAX_GO_INTENT 15
/* P2P Capability - Device Capability bitmap */
#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
/* P2P Capability - Group Capability bitmap */
#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
/* Invitation Flags */
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
/* P2P Manageability */
#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
enum p2p_status_code {
P2P_SC_SUCCESS = 0,
P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2,
P2P_SC_FAIL_LIMIT_REACHED = 3,
P2P_SC_FAIL_INVALID_PARAMS = 4,
P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5,
P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6,
P2P_SC_FAIL_NO_COMMON_CHANNELS = 7,
P2P_SC_FAIL_UNKNOWN_GROUP = 8,
P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
P2P_SC_FAIL_REJECTED_BY_USER = 11,
};
#define P2P_WILDCARD_SSID "DIRECT-"
#define P2P_WILDCARD_SSID_LEN 7
/* P2P action frames */
enum p2p_act_frame_type {
P2P_NOA = 0,
P2P_PRESENCE_REQ = 1,
P2P_PRESENCE_RESP = 2,
P2P_GO_DISC_REQ = 3
};
/* P2P public action frames */
enum p2p_action_frame_type {
P2P_GO_NEG_REQ = 0,
P2P_GO_NEG_RESP = 1,
P2P_GO_NEG_CONF = 2,
P2P_INVITATION_REQ = 3,
P2P_INVITATION_RESP = 4,
P2P_DEV_DISC_REQ = 5,
P2P_DEV_DISC_RESP = 6,
P2P_PROV_DISC_REQ = 7,
P2P_PROV_DISC_RESP = 8
};
enum p2p_service_protocol_type {
P2P_SERV_ALL_SERVICES = 0,
P2P_SERV_BONJOUR = 1,
P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3,
P2P_SERV_VENDOR_SPECIFIC = 255
};
enum p2p_sd_status {
P2P_SD_SUCCESS = 0,
P2P_SD_PROTO_NOT_AVAILABLE = 1,
P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
P2P_SD_BAD_REQUEST = 3
};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
/* cipher suite selectors */
#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
#define WLAN_CIPHER_SUITE_WEP40 0x000FAC01
#define WLAN_CIPHER_SUITE_TKIP 0x000FAC02
/* reserved: 0x000FAC03 */
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
#define WLAN_AKM_SUITE_PSK 0x000FAC02
#endif /* IEEE802_11_DEFS_H */

View file

@ -0,0 +1,75 @@
/*
* WPA Supplicant - privilege separation commands
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
enum privsep_cmd {
PRIVSEP_CMD_REGISTER,
PRIVSEP_CMD_UNREGISTER,
PRIVSEP_CMD_SCAN,
PRIVSEP_CMD_GET_SCAN_RESULTS,
PRIVSEP_CMD_ASSOCIATE,
PRIVSEP_CMD_GET_BSSID,
PRIVSEP_CMD_GET_SSID,
PRIVSEP_CMD_SET_KEY,
PRIVSEP_CMD_GET_CAPA,
PRIVSEP_CMD_L2_REGISTER,
PRIVSEP_CMD_L2_UNREGISTER,
PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
PRIVSEP_CMD_L2_SEND,
PRIVSEP_CMD_SET_COUNTRY,
};
struct privsep_cmd_associate
{
u8 bssid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
int freq;
int pairwise_suite;
int group_suite;
int key_mgmt_suite;
int auth_alg;
int mode;
size_t wpa_ie_len;
/* followed by wpa_ie_len bytes of wpa_ie */
};
struct privsep_cmd_set_key
{
int alg;
u8 addr[ETH_ALEN];
int key_idx;
int set_tx;
u8 seq[8];
size_t seq_len;
u8 key[32];
size_t key_len;
};
enum privsep_event {
PRIVSEP_EVENT_SCAN_RESULTS,
PRIVSEP_EVENT_ASSOC,
PRIVSEP_EVENT_DISASSOC,
PRIVSEP_EVENT_ASSOCINFO,
PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
PRIVSEP_EVENT_INTERFACE_STATUS,
PRIVSEP_EVENT_PMKID_CANDIDATE,
PRIVSEP_EVENT_STKSTART,
PRIVSEP_EVENT_FT_RESPONSE,
PRIVSEP_EVENT_RX_EAPOL,
};
#endif /* PRIVSEP_COMMANDS_H */

View file

@ -0,0 +1,10 @@
#ifndef VERSION_H
#define VERSION_H
#ifndef VERSION_STR_POSTFIX
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
#define VERSION_STR "0.8.x" VERSION_STR_POSTFIX
#endif /* VERSION_H */

View file

@ -0,0 +1,927 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
* Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "ieee802_11_defs.h"
#include "defs.h"
#include "wpa_common.h"
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
* @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
* @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
* Returns: 0 on success, -1 on failure
*
* Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
* to be cleared (all zeroes) when calling this function.
*
* Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
* description of the Key MIC calculation. It includes packet data from the
* beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
* happened during final editing of the standard and the correct behavior is
* defined in the last draft (IEEE 802.11i/D10).
*/
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
u8 *mic)
{
u8 hash[SHA1_MAC_LEN];
switch (ver) {
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
return hmac_md5(key, 16, buf, len, mic);
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
if (hmac_sha1(key, 16, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
case WPA_KEY_INFO_TYPE_AES_128_CMAC:
return omac1_aes_128(key, buf, len, mic);
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
default:
return -1;
}
return 0;
}
/**
* wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
* @pmk: Pairwise master key
* @pmk_len: Length of PMK
* @label: Label to use in derivation
* @addr1: AA or SA
* @addr2: SA or AA
* @nonce1: ANonce or SNonce
* @nonce2: SNonce or ANonce
* @ptk: Buffer for pairwise transient key
* @ptk_len: Length of PTK
* @use_sha256: Whether to use SHA256-based KDF
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
* Min(AA, SA) || Max(AA, SA) ||
* Min(ANonce, SNonce) || Max(ANonce, SNonce))
*
* STK = PRF-X(SMK, "Peer key expansion",
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
* Min(INonce, PNonce) || Max(INonce, PNonce))
*/
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
u8 *ptk, size_t ptk_len, int use_sha256)
{
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
} else {
os_memcpy(data, addr2, ETH_ALEN);
os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
}
if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
WPA_NONCE_LEN);
} else {
os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
WPA_NONCE_LEN);
}
#ifdef CONFIG_IEEE80211W
if (use_sha256)
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
ptk, ptk_len);
else
#endif /* CONFIG_IEEE80211W */
sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
ptk_len);
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
}
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
{
u8 *buf, *pos;
size_t buf_len;
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
pos = buf;
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, ap_addr, ETH_ALEN);
pos += ETH_ALEN;
*pos++ = transaction_seqnum;
if (rsnie) {
os_memcpy(pos, rsnie, rsnie_len);
pos += rsnie_len;
}
if (mdie) {
os_memcpy(pos, mdie, mdie_len);
pos += mdie_len;
}
if (ftie) {
struct rsn_ftie *_ftie;
os_memcpy(pos, ftie, ftie_len);
if (ftie_len < 2 + sizeof(*_ftie)) {
os_free(buf);
return -1;
}
_ftie = (struct rsn_ftie *) (pos + 2);
os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
pos += ftie_len;
}
if (ric) {
os_memcpy(pos, ric, ric_len);
pos += ric_len;
}
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
if (omac1_aes_128(kck, buf, pos - buf, mic)) {
os_free(buf);
return -1;
}
os_free(buf);
return 0;
}
#endif /* CONFIG_IEEE80211R */
#ifndef CONFIG_NO_WPA2
static int rsn_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
return WPA_CIPHER_NONE;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
return WPA_CIPHER_WEP40;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
return WPA_CIPHER_WEP104;
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
return 0;
}
static int rsn_key_mgmt_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
return WPA_KEY_MGMT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
return WPA_KEY_MGMT_PSK;
#ifdef CONFIG_IEEE80211R
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
return WPA_KEY_MGMT_FT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
return WPA_KEY_MGMT_FT_PSK;
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
return WPA_KEY_MGMT_IEEE8021X_SHA256;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
return WPA_KEY_MGMT_PSK_SHA256;
#endif /* CONFIG_IEEE80211W */
return 0;
}
#endif /* CONFIG_NO_WPA2 */
/**
* wpa_parse_wpa_ie_rsn - Parse RSN IE
* @rsn_ie: Buffer containing RSN IE
* @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
* @data: Pointer to structure that will be filled in with parsed data
* Returns: 0 on success, <0 on failure
*/
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
#ifndef CONFIG_NO_WPA2
const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
os_memset(data, 0, sizeof(*data));
data->proto = WPA_PROTO_RSN;
data->pairwise_cipher = WPA_CIPHER_CCMP;
data->group_cipher = WPA_CIPHER_CCMP;
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
#ifdef CONFIG_IEEE80211W
data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
#else /* CONFIG_IEEE80211W */
data->mgmt_group_cipher = 0;
#endif /* CONFIG_IEEE80211W */
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
return -1;
}
if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
__func__, (unsigned long) rsn_ie_len);
return -1;
}
hdr = (const struct rsn_ie_hdr *) rsn_ie;
if (hdr->elem_id != WLAN_EID_RSN ||
hdr->len != rsn_ie_len - 2 ||
WPA_GET_LE16(hdr->version) != RSN_VERSION) {
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
__func__);
return -2;
}
pos = (const u8 *) (hdr + 1);
left = rsn_ie_len - sizeof(*hdr);
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
#ifdef CONFIG_IEEE80211W
if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
"cipher", __func__);
return -1;
}
#endif /* CONFIG_IEEE80211W */
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
} else if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
__func__, left);
return -3;
}
if (left >= 2) {
data->pairwise_cipher = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
}
for (i = 0; i < count; i++) {
data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
#ifdef CONFIG_IEEE80211W
if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
"pairwise cipher", __func__);
return -1;
}
#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
return -5;
}
if (left >= 2) {
data->key_mgmt = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
}
for (i = 0; i < count; i++) {
data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
__func__);
return -7;
}
if (left >= 2) {
data->capabilities = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
}
if (left >= 2) {
data->num_pmkid = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (left < (int) data->num_pmkid * PMKID_LEN) {
wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
"(num_pmkid=%lu left=%d)",
__func__, (unsigned long) data->num_pmkid,
left);
data->num_pmkid = 0;
return -9;
} else {
data->pmkid = pos;
pos += data->num_pmkid * PMKID_LEN;
left -= data->num_pmkid * PMKID_LEN;
}
}
#ifdef CONFIG_IEEE80211W
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
wpa_printf(MSG_DEBUG, "%s: Unsupported management "
"group cipher 0x%x", __func__,
data->mgmt_group_cipher);
return -10;
}
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
#endif /* CONFIG_IEEE80211W */
if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
__func__, left);
}
return 0;
#else /* CONFIG_NO_WPA2 */
return -1;
#endif /* CONFIG_NO_WPA2 */
}
static int wpa_selector_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
return WPA_CIPHER_NONE;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
return WPA_CIPHER_WEP40;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
return WPA_CIPHER_TKIP;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
return WPA_CIPHER_CCMP;
if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
return WPA_CIPHER_WEP104;
return 0;
}
static int wpa_key_mgmt_to_bitfield(const u8 *s)
{
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
return WPA_KEY_MGMT_IEEE8021X;
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
return WPA_KEY_MGMT_PSK;
if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
return WPA_KEY_MGMT_WPA_NONE;
return 0;
}
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data)
{
const struct wpa_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
os_memset(data, 0, sizeof(*data));
data->proto = WPA_PROTO_WPA;
data->pairwise_cipher = WPA_CIPHER_TKIP;
data->group_cipher = WPA_CIPHER_TKIP;
data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
data->mgmt_group_cipher = 0;
if (wpa_ie_len == 0) {
/* No WPA IE - fail silently */
return -1;
}
if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
__func__, (unsigned long) wpa_ie_len);
return -1;
}
hdr = (const struct wpa_ie_hdr *) wpa_ie;
if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
hdr->len != wpa_ie_len - 2 ||
RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
WPA_GET_LE16(hdr->version) != WPA_VERSION) {
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
__func__);
return -2;
}
pos = (const u8 *) (hdr + 1);
left = wpa_ie_len - sizeof(*hdr);
if (left >= WPA_SELECTOR_LEN) {
data->group_cipher = wpa_selector_to_bitfield(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
} else if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
__func__, left);
return -3;
}
if (left >= 2) {
data->pairwise_cipher = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
"count %u left %u", __func__, count, left);
return -4;
}
for (i = 0; i < count; i++) {
data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
}
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
return -5;
}
if (left >= 2) {
data->key_mgmt = 0;
count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN) {
wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
"count %u left %u", __func__, count, left);
return -6;
}
for (i = 0; i < count; i++) {
data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
pos += WPA_SELECTOR_LEN;
left -= WPA_SELECTOR_LEN;
}
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
__func__);
return -7;
}
if (left >= 2) {
data->capabilities = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
}
if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
__func__, left);
}
return 0;
}
#ifdef CONFIG_IEEE80211R
/**
* wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
*
* IEEE Std 802.11r-2008 - 8.5.1.5.3
*/
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
{
u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
FT_R0KH_ID_MAX_LEN + ETH_ALEN];
u8 *pos, r0_key_data[48], hash[32];
const u8 *addr[2];
size_t len[2];
/*
* R0-Key-Data = KDF-384(XXKey, "FT-R0",
* SSIDlength || SSID || MDID || R0KHlength ||
* R0KH-ID || S0KH-ID)
* XXKey is either the second 256 bits of MSK or PSK.
* PMK-R0 = L(R0-Key-Data, 0, 256)
* PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
*/
if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return;
pos = buf;
*pos++ = ssid_len;
os_memcpy(pos, ssid, ssid_len);
pos += ssid_len;
os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
pos += MOBILITY_DOMAIN_ID_LEN;
*pos++ = r0kh_id_len;
os_memcpy(pos, r0kh_id, r0kh_id_len);
pos += r0kh_id_len;
os_memcpy(pos, s0kh_id, ETH_ALEN);
pos += ETH_ALEN;
sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
r0_key_data, sizeof(r0_key_data));
os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
/*
* PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
*/
addr[0] = (const u8 *) "FT-R0N";
len[0] = 6;
addr[1] = r0_key_data + PMK_LEN;
len[1] = 16;
sha256_vector(2, addr, len, hash);
os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
}
/**
* wpa_derive_pmk_r1_name - Derive PMKR1Name
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
const u8 *s1kh_id, u8 *pmk_r1_name)
{
u8 hash[32];
const u8 *addr[4];
size_t len[4];
/*
* PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
* R1KH-ID || S1KH-ID))
*/
addr[0] = (const u8 *) "FT-R1N";
len[0] = 6;
addr[1] = pmk_r0_name;
len[1] = WPA_PMK_NAME_LEN;
addr[2] = r1kh_id;
len[2] = FT_R1KH_ID_LEN;
addr[3] = s1kh_id;
len[3] = ETH_ALEN;
sha256_vector(4, addr, len, hash);
os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
}
/**
* wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
*
* IEEE Std 802.11r-2008 - 8.5.1.5.4
*/
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name)
{
u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
u8 *pos;
/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
pos = buf;
os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
pos += FT_R1KH_ID_LEN;
os_memcpy(pos, s1kh_id, ETH_ALEN);
pos += ETH_ALEN;
sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
}
/**
* wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
u8 *ptk, size_t ptk_len, u8 *ptk_name)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
* BSSID || STA-ADDR)
*/
pos = buf;
os_memcpy(pos, snonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
os_memcpy(pos, anonce, WPA_NONCE_LEN);
pos += WPA_NONCE_LEN;
os_memcpy(pos, bssid, ETH_ALEN);
pos += ETH_ALEN;
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
* ANonce || BSSID || STA-ADDR))
*/
addr[0] = pmk_r1_name;
len[0] = WPA_PMK_NAME_LEN;
addr[1] = (const u8 *) "FT-PTKN";
len[1] = 7;
addr[2] = snonce;
len[2] = WPA_NONCE_LEN;
addr[3] = anonce;
len[3] = WPA_NONCE_LEN;
addr[4] = bssid;
len[4] = ETH_ALEN;
addr[5] = sta_addr;
len[5] = ETH_ALEN;
sha256_vector(6, addr, len, hash);
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
}
#endif /* CONFIG_IEEE80211R */
/**
* rsn_pmkid - Calculate PMK identifier
* @pmk: Pairwise master key
* @pmk_len: Length of pmk in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: Buffer for PMKID
* @use_sha256: Whether to use SHA256-based KDF
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
*/
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256)
{
char *title = "PMK Name";
const u8 *addr[3];
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
unsigned char hash[SHA256_MAC_LEN];
addr[0] = (u8 *) title;
addr[1] = aa;
addr[2] = spa;
#ifdef CONFIG_IEEE80211W
if (use_sha256)
hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
os_memcpy(pmkid, hash, PMKID_LEN);
}
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
* Returns: Pointer to a text string of the cipher suite name
*/
const char * wpa_cipher_txt(int cipher)
{
switch (cipher) {
case WPA_CIPHER_NONE:
return "NONE";
case WPA_CIPHER_WEP40:
return "WEP-40";
case WPA_CIPHER_WEP104:
return "WEP-104";
case WPA_CIPHER_TKIP:
return "TKIP";
case WPA_CIPHER_CCMP:
return "CCMP";
case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
return "CCMP+TKIP";
default:
return "UNKNOWN";
}
}
/**
* wpa_key_mgmt_txt - Convert key management suite to a text string
* @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
* @proto: WPA/WPA2 version (WPA_PROTO_*)
* Returns: Pointer to a text string of the key management suite name
*/
const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
{
switch (key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
return "WPA2+WPA/IEEE 802.1X/EAP";
return proto == WPA_PROTO_RSN ?
"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
case WPA_KEY_MGMT_PSK:
if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
return "WPA2-PSK+WPA-PSK";
return proto == WPA_PROTO_RSN ?
"WPA2-PSK" : "WPA-PSK";
case WPA_KEY_MGMT_NONE:
return "NONE";
case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
return "IEEE 802.1X (no WPA)";
#ifdef CONFIG_IEEE80211R
case WPA_KEY_MGMT_FT_IEEE8021X:
return "FT-EAP";
case WPA_KEY_MGMT_FT_PSK:
return "FT-PSK";
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
case WPA_KEY_MGMT_IEEE8021X_SHA256:
return "WPA2-EAP-SHA256";
case WPA_KEY_MGMT_PSK_SHA256:
return "WPA2-PSK-SHA256";
#endif /* CONFIG_IEEE80211W */
default:
return "UNKNOWN";
}
}
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len)
{
if (ie1 == NULL || ie2 == NULL)
return -1;
if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
return 0; /* identical IEs */
#ifdef CONFIG_IEEE80211R
if (ft_initial_assoc) {
struct wpa_ie_data ie1d, ie2d;
/*
* The PMKID-List in RSN IE is different between Beacon/Probe
* Response/(Re)Association Request frames and EAPOL-Key
* messages in FT initial mobility domain association. Allow
* for this, but verify that other parts of the RSN IEs are
* identical.
*/
if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
return -1;
if (ie1d.proto == ie2d.proto &&
ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
ie1d.group_cipher == ie2d.group_cipher &&
ie1d.key_mgmt == ie2d.key_mgmt &&
ie1d.capabilities == ie2d.capabilities &&
ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
return 0;
}
#endif /* CONFIG_IEEE80211R */
return -1;
}
#ifdef CONFIG_IEEE80211R
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
int added = 0;
start = ies;
end = ies + ies_len;
while (start < end) {
if (*start == WLAN_EID_RSN)
break;
start += 2 + start[1];
}
if (start >= end) {
wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
"IEs data");
return -1;
}
wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
start, 2 + start[1]);
/* Find start of PMKID-Count */
rpos = start + 2;
rend = rpos + start[1];
/* Skip Version and Group Data Cipher Suite */
rpos += 2 + 4;
/* Skip Pairwise Cipher Suite Count and List */
rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
/* Skip AKM Suite Count and List */
rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
if (rpos == rend) {
/* Add RSN Capabilities */
os_memmove(rpos + 2, rpos, end - rpos);
*rpos++ = 0;
*rpos++ = 0;
} else {
/* Skip RSN Capabilities */
rpos += 2;
if (rpos > rend) {
wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
"IEs data");
return -1;
}
}
if (rpos == rend) {
/* No PMKID-Count field included; add it */
os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memcpy(rpos, pmkid, PMKID_LEN);
added += 2 + PMKID_LEN;
start[1] += 2 + PMKID_LEN;
} else {
/* PMKID-Count was included; use it */
if (WPA_GET_LE16(rpos) != 0) {
wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
"in RSN IE in EAPOL-Key data");
return -1;
}
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
os_memcpy(rpos, pmkid, PMKID_LEN);
added += PMKID_LEN;
start[1] += PMKID_LEN;
}
wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
"(PMKID inserted)", start, 2 + start[1]);
return added;
}
#endif /* CONFIG_IEEE80211R */

View file

@ -0,0 +1,361 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
* Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_COMMON_H
#define WPA_COMMON_H
#define WPA_MAX_SSID_LEN 32
/* IEEE 802.11i */
#define PMKID_LEN 16
#define PMK_LEN 32
#define WPA_REPLAY_COUNTER_LEN 8
#define WPA_NONCE_LEN 32
#define WPA_KEY_RSC_LEN 8
#define WPA_GMK_LEN 32
#define WPA_GTK_MAX_LEN 32
#define WPA_SELECTOR_LEN 4
#define WPA_VERSION 1
#define RSN_SELECTOR_LEN 4
#define RSN_VERSION 1
#define RSN_SELECTOR(a, b, c, d) \
((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
(u32) (d))
#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
#if 0
#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
#endif
#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#ifdef CONFIG_IEEE80211R
#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#endif /* CONFIG_IEEE80211R */
#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#if 0
#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#endif
#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#ifdef CONFIG_IEEE80211W
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#endif /* CONFIG_IEEE80211W */
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
*/
#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
#if 0
#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
#endif
#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
#ifdef CONFIG_PEERKEY
#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#endif /* CONFIG_PEERKEY */
#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#endif /* CONFIG_IEEE80211W */
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
#define RSN_NUM_REPLAY_COUNTERS_1 0
#define RSN_NUM_REPLAY_COUNTERS_2 1
#define RSN_NUM_REPLAY_COUNTERS_4 2
#define RSN_NUM_REPLAY_COUNTERS_16 3
#ifdef _MSC_VER
#pragma pack(push, 1)
#endif /* _MSC_VER */
#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
#endif /* CONFIG_IEEE80211W */
/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
#define WPA_CAPABILITY_PREAUTH BIT(0)
#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
/* B2-B3: PTKSA Replay Counter */
/* B4-B5: GTKSA Replay Counter */
#define WPA_CAPABILITY_MFPR BIT(6)
#define WPA_CAPABILITY_MFPC BIT(7)
/* B8: Reserved */
#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10)
#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
#define WPA_CAPABILITY_PBAC BIT(12)
#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
/* B14-B15: Reserved */
/* IEEE 802.11r */
#define MOBILITY_DOMAIN_ID_LEN 2
#define FT_R0KH_ID_MAX_LEN 48
#define FT_R1KH_ID_LEN 6
#define WPA_PMK_NAME_LEN 16
/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
#define WPA_KEY_INFO_TXRX BIT(6) /* group */
#define WPA_KEY_INFO_ACK BIT(7)
#define WPA_KEY_INFO_MIC BIT(8)
#define WPA_KEY_INFO_SECURE BIT(9)
#define WPA_KEY_INFO_ERROR BIT(10)
#define WPA_KEY_INFO_REQUEST BIT(11)
#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
struct wpa_eapol_key {
u8 type;
/* Note: key_info, key_length, and key_data_length are unaligned */
u8 key_info[2]; /* big endian */
u8 key_length[2]; /* big endian */
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
u8 key_nonce[WPA_NONCE_LEN];
u8 key_iv[16];
u8 key_rsc[WPA_KEY_RSC_LEN];
u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
u8 key_mic[16];
u8 key_data_length[2]; /* big endian */
/* followed by key_data_length bytes of key_data */
} STRUCT_PACKED;
/**
* struct wpa_ptk - WPA Pairwise Transient Key
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
*/
struct wpa_ptk {
u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
u8 tk1[16]; /* Temporal Key 1 (TK1) */
union {
u8 tk2[16]; /* Temporal Key 2 (TK2) */
struct {
u8 tx_mic_key[8];
u8 rx_mic_key[8];
} auth;
} u;
} STRUCT_PACKED;
/* WPA IE version 1
* 00-50-f2:1 (OUI:OUI type)
* 0x01 0x00 (version; little endian)
* (all following fields are optional:)
* Group Suite Selector (4 octets) (default: TKIP)
* Pairwise Suite Count (2 octets, little endian) (default: 1)
* Pairwise Suite List (4 * n octets) (default: TKIP)
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
* (default: unspec 802.1X)
* WPA Capabilities (2 octets, little endian) (default: 0)
*/
struct wpa_ie_hdr {
u8 elem_id;
u8 len;
u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
u8 version[2]; /* little endian */
} STRUCT_PACKED;
/* 1/4: PMKID
* 2/4: RSN IE
* 3/4: one or two RSN IEs + GTK IE (encrypted)
* 4/4: empty
* 1/2: GTK IE (encrypted)
* 2/2: empty
*/
/* RSN IE version 1
* 0x01 0x00 (version; little endian)
* (all following fields are optional:)
* Group Suite Selector (4 octets) (default: CCMP)
* Pairwise Suite Count (2 octets, little endian) (default: 1)
* Pairwise Suite List (4 * n octets) (default: CCMP)
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
* (default: unspec 802.1X)
* RSN Capabilities (2 octets, little endian) (default: 0)
* PMKID Count (2 octets) (default: 0)
* PMKID List (16 * n octets)
* Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
*/
struct rsn_ie_hdr {
u8 elem_id; /* WLAN_EID_RSN */
u8 len;
u8 version[2]; /* little endian */
} STRUCT_PACKED;
#ifdef CONFIG_PEERKEY
enum {
STK_MUI_4WAY_STA_AP = 1,
STK_MUI_4WAY_STAT_STA = 2,
STK_MUI_GTK = 3,
STK_MUI_SMK = 4
};
enum {
STK_ERR_STA_NR = 1,
STK_ERR_STA_NRSN = 2,
STK_ERR_CPHR_NS = 3,
STK_ERR_NO_STSL = 4
};
#endif /* CONFIG_PEERKEY */
struct rsn_error_kde {
be16 mui;
be16 error_type;
} STRUCT_PACKED;
#ifdef CONFIG_IEEE80211W
struct wpa_igtk_kde {
u8 keyid[2];
u8 pn[6];
u8 igtk[WPA_IGTK_LEN];
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
} STRUCT_PACKED;
#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
struct rsn_ftie {
u8 mic_control[2];
u8 mic[16];
u8 anonce[WPA_NONCE_LEN];
u8 snonce[WPA_NONCE_LEN];
/* followed by optional parameters */
} STRUCT_PACKED;
#define FTIE_SUBELEM_R1KH_ID 1
#define FTIE_SUBELEM_GTK 2
#define FTIE_SUBELEM_R0KH_ID 3
#define FTIE_SUBELEM_IGTK 4
struct rsn_rdie {
u8 id;
u8 descr_count;
le16 status_code;
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211R */
#ifdef _MSC_VER
#pragma pack(pop)
#endif /* _MSC_VER */
int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
u8 *mic);
void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
u8 *ptk, size_t ptk_len, int use_sha256);
#ifdef CONFIG_IEEE80211R
int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
const u8 *s1kh_id, u8 *pmk_r1_name);
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name);
void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
const u8 *sta_addr, const u8 *bssid,
const u8 *pmk_r1_name,
u8 *ptk, size_t ptk_len, u8 *ptk_name);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
int proto;
int pairwise_cipher;
int group_cipher;
int key_mgmt;
int capabilities;
size_t num_pmkid;
const u8 *pmkid;
int mgmt_group_cipher;
};
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data);
int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data);
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256);
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len);
int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
#endif /* WPA_COMMON_H */

View file

@ -0,0 +1,500 @@
/*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#ifdef CONFIG_CTRL_IFACE
#ifdef CONFIG_CTRL_IFACE_UNIX
#include <sys/un.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef ANDROID
#include <cutils/sockets.h>
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
#include "wpa_ctrl.h"
#include "common.h"
#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
#define CTRL_IFACE_SOCKET
#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
/**
* struct wpa_ctrl - Internal structure for control interface library
*
* This structure is used by the wpa_supplicant/hostapd control interface
* library to store internal data. Programs using the library should not touch
* this data directly. They can only use the pointer to the data structure as
* an identifier for the control interface connection and use this as one of
* the arguments for most of the control interface library functions.
*/
struct wpa_ctrl {
#ifdef CONFIG_CTRL_IFACE_UDP
int s;
struct sockaddr_in local;
struct sockaddr_in dest;
char *cookie;
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_CTRL_IFACE_UNIX
int s;
struct sockaddr_un local;
struct sockaddr_un dest;
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
HANDLE pipe;
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
};
#ifdef CONFIG_CTRL_IFACE_UNIX
#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
int ret;
size_t res;
int tries = 0;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
os_free(ctrl);
return NULL;
}
ctrl->local.sun_family = AF_UNIX;
counter++;
try_again:
ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
CONFIG_CTRL_IFACE_CLIENT_DIR "/"
CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
(int) getpid(), counter);
if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
tries++;
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
if (errno == EADDRINUSE && tries < 2) {
/*
* getpid() returns unique identifier for this instance
* of wpa_ctrl, so the existing socket file must have
* been left by unclean termination of an earlier run.
* Remove the file and try again.
*/
unlink(ctrl->local.sun_path);
goto try_again;
}
close(ctrl->s);
os_free(ctrl);
return NULL;
}
#ifdef ANDROID
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
/*
* If the ctrl_path isn't an absolute pathname, assume that
* it's the name of a socket in the Android reserved namespace.
* Otherwise, it's a normal UNIX domain socket appearing in the
* filesystem.
*/
if (ctrl_path != NULL && *ctrl_path != '/') {
char buf[21];
os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
if (socket_local_client_connect(
ctrl->s, buf,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_DGRAM) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
#endif /* ANDROID */
ctrl->dest.sun_family = AF_UNIX;
res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
sizeof(ctrl->dest.sun_path));
if (res >= sizeof(ctrl->dest.sun_path)) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
close(ctrl->s);
unlink(ctrl->local.sun_path);
os_free(ctrl);
return NULL;
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
if (ctrl == NULL)
return;
unlink(ctrl->local.sun_path);
if (ctrl->s >= 0)
close(ctrl->s);
os_free(ctrl);
}
#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_CTRL_IFACE_UDP
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
char buf[128];
size_t len;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
perror("socket");
os_free(ctrl);
return NULL;
}
ctrl->local.sin_family = AF_INET;
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
os_free(ctrl);
return NULL;
}
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
perror("connect");
close(ctrl->s);
os_free(ctrl);
return NULL;
}
len = sizeof(buf) - 1;
if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
buf[len] = '\0';
ctrl->cookie = os_strdup(buf);
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
close(ctrl->s);
os_free(ctrl->cookie);
os_free(ctrl);
}
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
int res;
fd_set rfds;
const char *_cmd;
char *cmd_buf = NULL;
size_t _cmd_len;
#ifdef CONFIG_CTRL_IFACE_UDP
if (ctrl->cookie) {
char *pos;
_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
cmd_buf = os_malloc(_cmd_len);
if (cmd_buf == NULL)
return -1;
_cmd = cmd_buf;
pos = cmd_buf;
os_strlcpy(pos, ctrl->cookie, _cmd_len);
pos += os_strlen(ctrl->cookie);
*pos++ = ' ';
os_memcpy(pos, cmd, cmd_len);
} else
#endif /* CONFIG_CTRL_IFACE_UDP */
{
_cmd = cmd;
_cmd_len = cmd_len;
}
if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
os_free(cmd_buf);
return -1;
}
os_free(cmd_buf);
for (;;) {
tv.tv_sec = 10;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
if (res < 0)
return res;
if (FD_ISSET(ctrl->s, &rfds)) {
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
if (res > 0 && reply[0] == '<') {
/* This is an unsolicited message from
* wpa_supplicant, not the reply to the
* request. Use msg_cb to report this to the
* caller. */
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
if ((size_t) res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
}
continue;
}
*reply_len = res;
break;
} else {
return -2;
}
}
return 0;
}
#endif /* CTRL_IFACE_SOCKET */
static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
{
char buf[10];
int ret;
size_t len = 10;
ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
buf, &len, NULL);
if (ret < 0)
return ret;
if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
return 0;
return -1;
}
int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 1);
}
int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
{
return wpa_ctrl_attach_helper(ctrl, 0);
}
#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;
res = recv(ctrl->s, reply, *reply_len, 0);
if (res < 0)
return res;
*reply_len = res;
return 0;
}
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
struct timeval tv;
fd_set rfds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
return FD_ISSET(ctrl->s, &rfds);
}
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return ctrl->s;
}
#endif /* CTRL_IFACE_SOCKET */
#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
#ifndef WPA_SUPPLICANT_NAMED_PIPE
#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
#endif
#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
DWORD mode;
TCHAR name[256];
int i, ret;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
os_memset(ctrl, 0, sizeof(*ctrl));
#ifdef UNICODE
if (ctrl_path == NULL)
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
else
ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
ctrl_path);
#else /* UNICODE */
if (ctrl_path == NULL)
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
else
ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
ctrl_path);
#endif /* UNICODE */
if (ret < 0 || ret >= 256) {
os_free(ctrl);
return NULL;
}
for (i = 0; i < 10; i++) {
ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
/*
* Current named pipe server side in wpa_supplicant is
* re-opening the pipe for new clients only after the previous
* one is taken into use. This leaves a small window for race
* conditions when two connections are being opened at almost
* the same time. Retry if that was the case.
*/
if (ctrl->pipe != INVALID_HANDLE_VALUE ||
GetLastError() != ERROR_PIPE_BUSY)
break;
WaitNamedPipe(name, 1000);
}
if (ctrl->pipe == INVALID_HANDLE_VALUE) {
os_free(ctrl);
return NULL;
}
mode = PIPE_READMODE_MESSAGE;
if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
CloseHandle(ctrl->pipe);
os_free(ctrl);
return NULL;
}
return ctrl;
}
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
CloseHandle(ctrl->pipe);
os_free(ctrl);
}
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
{
DWORD written;
DWORD readlen = *reply_len;
if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
return -1;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
return -1;
*reply_len = readlen;
return 0;
}
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
DWORD len = *reply_len;
if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
return -1;
*reply_len = len;
return 0;
}
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
DWORD left;
if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
return -1;
return left ? 1 : 0;
}
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return -1;
}
#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
#endif /* CONFIG_CTRL_IFACE */

View file

@ -0,0 +1,274 @@
/*
* wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef WPA_CTRL_H
#define WPA_CTRL_H
#ifdef __cplusplus
extern "C" {
#endif
/* wpa_supplicant control interface - fixed message prefixes */
/** Interactive request for identity/password/pin */
#define WPA_CTRL_REQ "CTRL-REQ-"
/** Response to identity/password/pin request */
#define WPA_CTRL_RSP "CTRL-RSP-"
/* Event messages with fixed prefix */
/** Authentication completed successfully and data connection enabled */
#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
/** Disconnected, data connection is not available */
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
/** Association rejected during connection attempt */
#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
/** wpa_supplicant is exiting */
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
/** Password change was completed successfully */
#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
/** EAP-Request/Notification received */
#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
/** EAP authentication started (EAP-Request/Identity received) */
#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
/** EAP method proposed by the server */
#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
/** EAP method selected */
#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
/** EAP peer certificate from TLS */
#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP authentication completed successfully */
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
/** wpa_supplicant state change */
#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
/** A new BSS entry was added (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
/** WPS overlap detected in PBC mode */
#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
/** Available WPS AP with active PBC found in scan results */
#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
/** Available WPS AP with our address as authorized in scan results */
#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
/** Available WPS AP with recently selected PIN registrar found in scan results
*/
#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
/** Available WPS AP found in scan results */
#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
/** A new credential received */
#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
/** M2D received */
#define WPS_EVENT_M2D "WPS-M2D "
/** WPS registration failed after M2/M2D */
#define WPS_EVENT_FAIL "WPS-FAIL "
/** WPS registration completed successfully */
#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
/** WPS enrollment attempt timed out and was terminated */
#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
/* WPS ER events */
#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
/** P2P device found */
#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
/** A P2P device requested GO negotiation, but we were not ready to start the
* negotiation */
#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
/* parameters: <peer address> <PIN> */
#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
/* parameters: <peer address> */
#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
/* parameters: <src addr> <update indicator> <TLVs> */
#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
/* wpa_supplicant/hostapd control interface access */
/**
* wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
* Returns: Pointer to abstract control interface data or %NULL on failure
*
* This function is used to open a control interface to wpa_supplicant/hostapd.
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
* is configured in wpa_supplicant/hostapd and other programs using the control
* interface need to use matching path configuration.
*/
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/**
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
*
* This function is used to close a control interface.
*/
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
* @ctrl: Control interface data from wpa_ctrl_open()
* @cmd: Command; usually, ASCII text, e.g., "PING"
* @cmd_len: Length of the cmd in bytes
* @reply: Buffer for the response
* @reply_len: Reply buffer length
* @msg_cb: Callback function for unsolicited messages or %NULL if not used
* Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
*
* This function is used to send commands to wpa_supplicant/hostapd. Received
* response will be written to reply and reply_len is set to the actual length
* of the reply. This function will block for up to two seconds while waiting
* for the reply. If unsolicited messages are received, the blocking time may
* be longer.
*
* msg_cb can be used to register a callback function that will be called for
* unsolicited messages received while waiting for the command response. These
* messages may be received if wpa_ctrl_request() is called at the same time as
* wpa_supplicant/hostapd is sending such a message. This can happen only if
* the program has used wpa_ctrl_attach() to register itself as a monitor for
* event messages. Alternatively to msg_cb, programs can register two control
* interface connections and use one of them for commands and the other one for
* receiving event messages, in other words, call wpa_ctrl_attach() only for
* the control interface connection that will be used for event messages.
*/
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len));
/**
* wpa_ctrl_attach - Register as an event monitor for the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function registers the control interface connection as a monitor for
* wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
* control interface connection starts receiving event messages that can be
* read with wpa_ctrl_recv().
*/
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_detach - Unregister event monitor from the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 0 on success, -1 on failure, -2 on timeout
*
* This function unregisters the control interface connection as a monitor for
* wpa_supplicant/hostapd events, i.e., cancels the registration done with
* wpa_ctrl_attach().
*/
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_recv - Receive a pending control interface message
* @ctrl: Control interface data from wpa_ctrl_open()
* @reply: Buffer for the message data
* @reply_len: Length of the reply buffer
* Returns: 0 on success, -1 on failure
*
* This function will receive a pending control interface message. This
* function will block if no messages are available. The received response will
* be written to reply and reply_len is set to the actual length of the reply.
* wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
* must have been used to register the control interface as an event monitor.
*/
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/**
* wpa_ctrl_pending - Check whether there are pending event messages
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: 1 if there are pending messages, 0 if no, or -1 on error
*
* This function will check whether there are any pending control interface
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
* only used for event messages, i.e., wpa_ctrl_attach() must have been used to
* register the control interface as an event monitor.
*/
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
/**
* wpa_ctrl_get_fd - Get file descriptor used by the control interface
* @ctrl: Control interface data from wpa_ctrl_open()
* Returns: File descriptor used for the connection
*
* This function can be used to get the file descriptor that is used for the
* control interface connection. The returned value can be used, e.g., with
* select() while waiting for multiple events.
*
* The returned file descriptor must not be used directly for sending or
* receiving packets; instead, the library functions wpa_ctrl_request() and
* wpa_ctrl_recv() must be used for this.
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
#ifdef CONFIG_CTRL_IFACE_UDP
#define WPA_CTRL_IFACE_PORT 9877
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef __cplusplus
}
#endif
#endif /* WPA_CTRL_H */

1
hostapd-0.8/src/crypto/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
libcrypto.a

View file

@ -0,0 +1,56 @@
all: libcrypto.a
clean:
rm -f *~ *.o *.d libcrypto.a
install:
@echo Nothing to be made.
include ../lib.rules
CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
#CFLAGS += -DALL_DH_GROUPS
LIB_OBJS= \
aes-cbc.o \
aes-ctr.o \
aes-eax.o \
aes-encblock.o \
aes-internal.o \
aes-internal-dec.o \
aes-internal-enc.o \
aes-omac1.o \
aes-unwrap.o \
aes-wrap.o \
des-internal.o \
dh_group5.o \
dh_groups.o \
md4-internal.o \
md5.o \
md5-internal.o \
md5-non-fips.o \
milenage.o \
ms_funcs.o \
rc4.o \
sha1.o \
sha1-internal.o \
sha1-pbkdf2.o \
sha1-tlsprf.o \
sha1-tprf.o \
sha256.o \
sha256-internal.o
LIB_OBJS += crypto_internal.o
LIB_OBJS += crypto_internal-cipher.o
LIB_OBJS += crypto_internal-modexp.o
LIB_OBJS += crypto_internal-rsa.o
LIB_OBJS += tls_internal.o
LIB_OBJS += fips_prf_internal.o
libcrypto.a: $(LIB_OBJS)
$(AR) crT $@ $?
-include $(OBJS:%.o=%.d)

View file

@ -0,0 +1,86 @@
/*
* AES-128 CBC
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_cbc_encrypt - AES-128 CBC encryption
* @key: Encryption key
* @iv: Encryption IV for CBC mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes (must be divisible by 16)
* Returns: 0 on success, -1 on failure
*/
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memcpy(cbc, iv, AES_BLOCK_SIZE);
blocks = data_len / AES_BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
for (j = 0; j < AES_BLOCK_SIZE; j++)
cbc[j] ^= pos[j];
aes_encrypt(ctx, cbc, cbc);
os_memcpy(pos, cbc, AES_BLOCK_SIZE);
pos += AES_BLOCK_SIZE;
}
aes_encrypt_deinit(ctx);
return 0;
}
/**
* aes_128_cbc_decrypt - AES-128 CBC decryption
* @key: Decryption key
* @iv: Decryption IV for CBC mode (16 bytes)
* @data: Data to decrypt in-place
* @data_len: Length of data in bytes (must be divisible by 16)
* Returns: 0 on success, -1 on failure
*/
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memcpy(cbc, iv, AES_BLOCK_SIZE);
blocks = data_len / AES_BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, pos, AES_BLOCK_SIZE);
aes_decrypt(ctx, pos, pos);
for (j = 0; j < AES_BLOCK_SIZE; j++)
pos[j] ^= cbc[j];
os_memcpy(cbc, tmp, AES_BLOCK_SIZE);
pos += AES_BLOCK_SIZE;
}
aes_decrypt_deinit(ctx);
return 0;
}

View file

@ -0,0 +1,61 @@
/*
* AES-128 CTR
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_ctr_encrypt - AES-128 CTR mode encryption
* @key: Key for encryption (16 bytes)
* @nonce: Nonce for counter mode (16 bytes)
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* Returns: 0 on success, -1 on failure
*/
int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len)
{
void *ctx;
size_t j, len, left = data_len;
int i;
u8 *pos = data;
u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memcpy(counter, nonce, AES_BLOCK_SIZE);
while (left > 0) {
aes_encrypt(ctx, counter, buf);
len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
for (j = 0; j < len; j++)
pos[j] ^= buf[j];
pos += len;
left -= len;
for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
counter[i]++;
if (counter[i])
break;
}
}
aes_encrypt_deinit(ctx);
return 0;
}

View file

@ -0,0 +1,151 @@
/*
* AES-128 EAX
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_eax_encrypt - AES-128 EAX mode encryption
* @key: Key for encryption (16 bytes)
* @nonce: Nonce for counter mode
* @nonce_len: Nonce length in bytes
* @hdr: Header data to be authenticity protected
* @hdr_len: Length of the header data bytes
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* @tag: 16-byte tag value
* Returns: 0 on success, -1 on failure
*/
int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag)
{
u8 *buf;
size_t buf_len;
u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
data_mac[AES_BLOCK_SIZE];
int i, ret = -1;
if (nonce_len > data_len)
buf_len = nonce_len;
else
buf_len = data_len;
if (hdr_len > buf_len)
buf_len = hdr_len;
buf_len += 16;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
os_memset(buf, 0, 15);
buf[15] = 0;
os_memcpy(buf + 16, nonce, nonce_len);
if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac))
goto fail;
buf[15] = 1;
os_memcpy(buf + 16, hdr, hdr_len);
if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac))
goto fail;
if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len))
goto fail;
buf[15] = 2;
os_memcpy(buf + 16, data, data_len);
if (omac1_aes_128(key, buf, 16 + data_len, data_mac))
goto fail;
for (i = 0; i < AES_BLOCK_SIZE; i++)
tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
ret = 0;
fail:
os_free(buf);
return ret;
}
/**
* aes_128_eax_decrypt - AES-128 EAX mode decryption
* @key: Key for decryption (16 bytes)
* @nonce: Nonce for counter mode
* @nonce_len: Nonce length in bytes
* @hdr: Header data to be authenticity protected
* @hdr_len: Length of the header data bytes
* @data: Data to encrypt in-place
* @data_len: Length of data in bytes
* @tag: 16-byte tag value
* Returns: 0 on success, -1 on failure, -2 if tag does not match
*/
int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag)
{
u8 *buf;
size_t buf_len;
u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
data_mac[AES_BLOCK_SIZE];
int i;
if (nonce_len > data_len)
buf_len = nonce_len;
else
buf_len = data_len;
if (hdr_len > buf_len)
buf_len = hdr_len;
buf_len += 16;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
os_memset(buf, 0, 15);
buf[15] = 0;
os_memcpy(buf + 16, nonce, nonce_len);
if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) {
os_free(buf);
return -1;
}
buf[15] = 1;
os_memcpy(buf + 16, hdr, hdr_len);
if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) {
os_free(buf);
return -1;
}
buf[15] = 2;
os_memcpy(buf + 16, data, data_len);
if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) {
os_free(buf);
return -1;
}
os_free(buf);
for (i = 0; i < AES_BLOCK_SIZE; i++) {
if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
return -2;
}
return aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
}

View file

@ -0,0 +1,38 @@
/*
* AES encrypt_block
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_128_encrypt_block - Perform one AES 128-bit block operation
* @key: Key for AES
* @in: Input data (16 bytes)
* @out: Output of the AES block operation (16 bytes)
* Returns: 0 on success, -1 on failure
*/
int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
{
void *ctx;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
aes_encrypt(ctx, in, out);
aes_encrypt_deinit(ctx);
return 0;
}

View file

@ -0,0 +1,151 @@
/*
* AES (Rijndael) cipher - decrypt
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes_i.h"
/**
* Expand the cipher key into the decryption key schedule.
*
* @return the number of rounds for the given cipher key size.
*/
void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
{
int Nr = 10, i, j;
u32 temp;
/* expand the cipher key: */
rijndaelKeySetupEnc(rk, cipherKey);
/* invert the order of the round keys: */
for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
temp = rk[i ]; rk[i ] = rk[j ]; rk[j ] = temp;
temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
}
/* apply the inverse MixColumn transform to all round keys but the
* first and the last: */
for (i = 1; i < Nr; i++) {
rk += 4;
for (j = 0; j < 4; j++) {
rk[j] = TD0_(TE4((rk[j] >> 24) )) ^
TD1_(TE4((rk[j] >> 16) & 0xff)) ^
TD2_(TE4((rk[j] >> 8) & 0xff)) ^
TD3_(TE4((rk[j] ) & 0xff));
}
}
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
u32 *rk;
if (len != 16)
return NULL;
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
rijndaelKeySetupDec(rk, key);
return rk;
}
static void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32(ct ) ^ rk[0];
s1 = GETU32(ct + 4) ^ rk[1];
s2 = GETU32(ct + 8) ^ rk[2];
s3 = GETU32(ct + 12) ^ rk[3];
#define ROUND(i,d,s) \
d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
#ifdef FULL_UNROLL
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
ROUND(4,s,t);
ROUND(5,t,s);
ROUND(6,s,t);
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
rk += Nr << 2;
#else /* !FULL_UNROLL */
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;) {
ROUND(1,t,s);
rk += 8;
if (--r == 0)
break;
ROUND(0,s,t);
}
#endif /* ?FULL_UNROLL */
#undef ROUND
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
PUTU32(pt , s0);
s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
PUTU32(pt + 4, s1);
s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
PUTU32(pt + 8, s2);
s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
PUTU32(pt + 12, s3);
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
rijndaelDecrypt(ctx, crypt, plain);
}
void aes_decrypt_deinit(void *ctx)
{
os_memset(ctx, 0, AES_PRIV_SIZE);
os_free(ctx);
}

View file

@ -0,0 +1,121 @@
/*
* AES (Rijndael) cipher - encrypt
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes_i.h"
void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
/*
* map byte array block to cipher state
* and add initial round key:
*/
s0 = GETU32(pt ) ^ rk[0];
s1 = GETU32(pt + 4) ^ rk[1];
s2 = GETU32(pt + 8) ^ rk[2];
s3 = GETU32(pt + 12) ^ rk[3];
#define ROUND(i,d,s) \
d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
#ifdef FULL_UNROLL
ROUND(1,t,s);
ROUND(2,s,t);
ROUND(3,t,s);
ROUND(4,s,t);
ROUND(5,t,s);
ROUND(6,s,t);
ROUND(7,t,s);
ROUND(8,s,t);
ROUND(9,t,s);
rk += Nr << 2;
#else /* !FULL_UNROLL */
/* Nr - 1 full rounds: */
r = Nr >> 1;
for (;;) {
ROUND(1,t,s);
rk += 8;
if (--r == 0)
break;
ROUND(0,s,t);
}
#endif /* ?FULL_UNROLL */
#undef ROUND
/*
* apply last round and
* map cipher state to byte array block:
*/
s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
PUTU32(ct , s0);
s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
PUTU32(ct + 4, s1);
s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
PUTU32(ct + 8, s2);
s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
PUTU32(ct + 12, s3);
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
u32 *rk;
if (len != 16)
return NULL;
rk = os_malloc(AES_PRIV_SIZE);
if (rk == NULL)
return NULL;
rijndaelKeySetupEnc(rk, key);
return rk;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
rijndaelEncrypt(ctx, plain, crypt);
}
void aes_encrypt_deinit(void *ctx)
{
os_memset(ctx, 0, AES_PRIV_SIZE);
os_free(ctx);
}

View file

@ -0,0 +1,805 @@
/*
* AES (Rijndael) cipher
*
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
* - use C pre-processor to make it easier to change S table access
* - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes_i.h"
/*
* rijndael-alg-fst.c
*
* @version 3.0 (December 2000)
*
* Optimised ANSI C code for the Rijndael cipher (now AES)
*
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
* @author Paulo Barreto <paulo.barreto@terra.com.br>
*
* This code is hereby placed in the public domain.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
Te0[x] = S [x].[02, 01, 01, 03];
Te1[x] = S [x].[03, 02, 01, 01];
Te2[x] = S [x].[01, 03, 02, 01];
Te3[x] = S [x].[01, 01, 03, 02];
Te4[x] = S [x].[01, 01, 01, 01];
Td0[x] = Si[x].[0e, 09, 0d, 0b];
Td1[x] = Si[x].[0b, 0e, 09, 0d];
Td2[x] = Si[x].[0d, 0b, 0e, 09];
Td3[x] = Si[x].[09, 0d, 0b, 0e];
Td4[x] = Si[x].[01, 01, 01, 01];
*/
const u32 Te0[256] = {
0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};
#ifndef AES_SMALL_TABLES
const u32 Te1[256] = {
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
};
const u32 Te2[256] = {
0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
};
const u32 Te3[256] = {
0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
};
const u32 Te4[256] = {
0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
};
#endif /* AES_SMALL_TABLES */
const u32 Td0[256] = {
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
};
#ifndef AES_SMALL_TABLES
const u32 Td1[256] = {
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
};
const u32 Td2[256] = {
0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
};
const u32 Td3[256] = {
0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
};
const u32 Td4[256] = {
0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
};
const u32 rcon[] = {
0x01000000, 0x02000000, 0x04000000, 0x08000000,
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#else /* AES_SMALL_TABLES */
const u8 Td4s[256] = {
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
};
const u8 rcons[] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
#endif /* AES_SMALL_TABLES */
/**
* Expand the cipher key into the encryption key schedule.
*
* @return the number of rounds for the given cipher key size.
*/
void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
{
int i;
u32 temp;
rk[0] = GETU32(cipherKey );
rk[1] = GETU32(cipherKey + 4);
rk[2] = GETU32(cipherKey + 8);
rk[3] = GETU32(cipherKey + 12);
for (i = 0; i < 10; i++) {
temp = rk[3];
rk[4] = rk[0] ^
TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
RCON(i);
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
rk += 4;
}
}

View file

@ -0,0 +1,124 @@
/*
* One-key CBC MAC (OMAC1) hash with AES-128
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
static void gf_mulx(u8 *pad)
{
int i, carry;
carry = pad[0] & 0x80;
for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
pad[AES_BLOCK_SIZE - 1] <<= 1;
if (carry)
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
}
/**
* omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
* @key: 128-bit key for the hash operation
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
total_len = 0;
for (e = 0; e < num_elem; e++)
total_len += len[e];
left = total_len;
e = 0;
pos = addr[0];
end = pos + len[0];
while (left >= AES_BLOCK_SIZE) {
for (i = 0; i < AES_BLOCK_SIZE; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
e++;
pos = addr[e];
end = pos + len[e];
}
}
if (left > AES_BLOCK_SIZE)
aes_encrypt(ctx, cbc, cbc);
left -= AES_BLOCK_SIZE;
}
os_memset(pad, 0, AES_BLOCK_SIZE);
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
if (left || total_len == 0) {
for (i = 0; i < left; i++) {
cbc[i] ^= *pos++;
if (pos >= end) {
e++;
pos = addr[e];
end = pos + len[e];
}
}
cbc[left] ^= 0x80;
gf_mulx(pad);
}
for (i = 0; i < AES_BLOCK_SIZE; i++)
pad[i] ^= cbc[i];
aes_encrypt(ctx, pad, mac);
aes_encrypt_deinit(ctx);
return 0;
}
/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data_len: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
* Returns: 0 on success, -1 on failure
*
* This is a mode for using block cipher (AES in this case) for authentication.
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}

View file

@ -0,0 +1,79 @@
/*
* AES key unwrap (128-bit KEK, RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: Key encryption key (KEK)
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
* @plain: Plaintext key, n * 64 bits
* Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
{
u8 a[8], *r, b[16];
int i, j;
void *ctx;
/* 1) Initialize variables. */
os_memcpy(a, cipher, 8);
r = plain;
os_memcpy(r, cipher + 8, 8 * n);
ctx = aes_decrypt_init(kek, 16);
if (ctx == NULL)
return -1;
/* 2) Compute intermediate values.
* For j = 5 to 0
* For i = n to 1
* B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
* A = MSB(64, B)
* R[i] = LSB(64, B)
*/
for (j = 5; j >= 0; j--) {
r = plain + (n - 1) * 8;
for (i = n; i >= 1; i--) {
os_memcpy(b, a, 8);
b[7] ^= n * j + i;
os_memcpy(b + 8, r, 8);
aes_decrypt(ctx, b, b);
os_memcpy(a, b, 8);
os_memcpy(r, b + 8, 8);
r -= 8;
}
}
aes_decrypt_deinit(ctx);
/* 3) Output results.
*
* These are already in @plain due to the location of temporary
* variables. Just verify that the IV matches with the expected value.
*/
for (i = 0; i < 8; i++) {
if (a[i] != 0xa6)
return -1;
}
return 0;
}

View file

@ -0,0 +1,76 @@
/*
* AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
/**
* aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* @kek: 16-octet Key encryption key (KEK)
* @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
* bytes
* @plain: Plaintext key to be wrapped, n * 64 bits
* @cipher: Wrapped key, (n + 1) * 64 bits
* Returns: 0 on success, -1 on failure
*/
int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
{
u8 *a, *r, b[16];
int i, j;
void *ctx;
a = cipher;
r = cipher + 8;
/* 1) Initialize variables. */
os_memset(a, 0xa6, 8);
os_memcpy(r, plain, 8 * n);
ctx = aes_encrypt_init(kek, 16);
if (ctx == NULL)
return -1;
/* 2) Calculate intermediate values.
* For j = 0 to 5
* For i=1 to n
* B = AES(K, A | R[i])
* A = MSB(64, B) ^ t where t = (n*j)+i
* R[i] = LSB(64, B)
*/
for (j = 0; j <= 5; j++) {
r = cipher + 8;
for (i = 1; i <= n; i++) {
os_memcpy(b, a, 8);
os_memcpy(b + 8, r, 8);
aes_encrypt(ctx, b, b);
os_memcpy(a, b, 8);
a[7] ^= n * j + i;
os_memcpy(r, b + 8, 8);
r += 8;
}
}
aes_encrypt_deinit(ctx);
/* 3) Output the results.
*
* These are already in @cipher due to the location of temporary
* variables.
*/
return 0;
}

View file

@ -0,0 +1,27 @@
/*
* AES functions
* Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_H
#define AES_H
#define AES_BLOCK_SIZE 16
void * aes_encrypt_init(const u8 *key, size_t len);
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
void aes_encrypt_deinit(void *ctx);
void * aes_decrypt_init(const u8 *key, size_t len);
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
#endif /* AES_H */

View file

@ -0,0 +1,122 @@
/*
* AES (Rijndael) cipher
* Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_I_H
#define AES_I_H
#include "aes.h"
/* #define FULL_UNROLL */
#define AES_SMALL_TABLES
extern const u32 Te0[256];
extern const u32 Te1[256];
extern const u32 Te2[256];
extern const u32 Te3[256];
extern const u32 Te4[256];
extern const u32 Td0[256];
extern const u32 Td1[256];
extern const u32 Td2[256];
extern const u32 Td3[256];
extern const u32 Td4[256];
extern const u32 rcon[10];
extern const u8 Td4s[256];
extern const u8 rcons[10];
#ifndef AES_SMALL_TABLES
#define RCON(i) rcon[(i)]
#define TE0(i) Te0[((i) >> 24) & 0xff]
#define TE1(i) Te1[((i) >> 16) & 0xff]
#define TE2(i) Te2[((i) >> 8) & 0xff]
#define TE3(i) Te3[(i) & 0xff]
#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
#define TE4(i) (Te4[(i)] & 0x000000ff)
#define TD0(i) Td0[((i) >> 24) & 0xff]
#define TD1(i) Td1[((i) >> 16) & 0xff]
#define TD2(i) Td2[((i) >> 8) & 0xff]
#define TD3(i) Td3[(i) & 0xff]
#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) Td1[(i) & 0xff]
#define TD2_(i) Td2[(i) & 0xff]
#define TD3_(i) Td3[(i) & 0xff]
#else /* AES_SMALL_TABLES */
#define RCON(i) (rcons[(i)] << 24)
static inline u32 rotr(u32 val, int bits)
{
return (val >> bits) | (val << (32 - bits));
}
#define TE0(i) Te0[((i) >> 24) & 0xff]
#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
#define TE3(i) rotr(Te0[(i) & 0xff], 24)
#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
#define TD0(i) Td0[((i) >> 24) & 0xff]
#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
#define TD3(i) rotr(Td0[(i) & 0xff], 24)
#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
#define TD44(i) (Td4s[(i) & 0xff])
#define TD0_(i) Td0[(i) & 0xff]
#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
#endif /* AES_SMALL_TABLES */
#ifdef _MSC_VER
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
#define GETU32(p) SWAP(*((u32 *)(p)))
#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
#else
#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
#define PUTU32(ct, st) { \
(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
#endif
#define AES_PRIV_SIZE (4 * 44)
void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[]);
#endif /* AES_I_H */

View file

@ -0,0 +1,48 @@
/*
* AES-based functions
*
* - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
* - One-Key CBC MAC (OMAC1) hash with AES-128
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef AES_WRAP_H
#define AES_WRAP_H
int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len,
u8 *mac);
int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
int __must_check aes_128_eax_encrypt(const u8 *key,
const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag);
int __must_check aes_128_eax_decrypt(const u8 *key,
const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag);
int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
size_t data_len);
#endif /* AES_WRAP_H */

View file

@ -0,0 +1,469 @@
/*
* WPA Supplicant / wrapper functions for crypto libraries
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*
* This file defines the cryptographic functions that need to be implemented
* for wpa_supplicant and hostapd. When TLS is not used, internal
* implementation of MD5, SHA1, and AES is used and no external libraries are
* required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
* crypto library used by the TLS implementation is expected to be used for
* non-TLS needs, too, in order to save space by not implementing these
* functions twice.
*
* Wrapper code for using each crypto library is in its own file (crypto*.c)
* and one of these files is build and linked in to provide the functions
* defined here.
*/
#ifndef CRYPTO_H
#define CRYPTO_H
/**
* md4_vector - MD4 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
/**
* md5_vector - MD5 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
#ifdef CONFIG_FIPS
/**
* md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed)
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac);
#else /* CONFIG_FIPS */
#define md5_vector_non_fips_allow md5_vector
#endif /* CONFIG_FIPS */
/**
* sha1_vector - SHA-1 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
* fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
* @seed: Seed/key for the PRF
* @seed_len: Seed length in bytes
* @x: Buffer for PRF output
* @xlen: Output length in bytes
* Returns: 0 on success, -1 on failure
*
* This function implements random number generation specified in NIST FIPS
* Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
* SHA-1, but has different message padding.
*/
int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x,
size_t xlen);
/**
* sha256_vector - SHA256 hash for data vector
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash
* Returns: 0 on success, -1 on failure
*/
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
* des_encrypt - Encrypt one block with DES
* @clear: 8 octets (in)
* @key: 7 octets (in) (no parity bits included)
* @cypher: 8 octets (out)
*/
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
/**
* aes_encrypt_init - Initialize AES for encryption
* @key: Encryption key
* @len: Key length in bytes (usually 16, i.e., 128 bits)
* Returns: Pointer to context data or %NULL on failure
*/
void * aes_encrypt_init(const u8 *key, size_t len);
/**
* aes_encrypt - Encrypt one AES block
* @ctx: Context pointer from aes_encrypt_init()
* @plain: Plaintext data to be encrypted (16 bytes)
* @crypt: Buffer for the encrypted data (16 bytes)
*/
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
/**
* aes_encrypt_deinit - Deinitialize AES encryption
* @ctx: Context pointer from aes_encrypt_init()
*/
void aes_encrypt_deinit(void *ctx);
/**
* aes_decrypt_init - Initialize AES for decryption
* @key: Decryption key
* @len: Key length in bytes (usually 16, i.e., 128 bits)
* Returns: Pointer to context data or %NULL on failure
*/
void * aes_decrypt_init(const u8 *key, size_t len);
/**
* aes_decrypt - Decrypt one AES block
* @ctx: Context pointer from aes_encrypt_init()
* @crypt: Encrypted data (16 bytes)
* @plain: Buffer for the decrypted data (16 bytes)
*/
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
/**
* aes_decrypt_deinit - Deinitialize AES decryption
* @ctx: Context pointer from aes_encrypt_init()
*/
void aes_decrypt_deinit(void *ctx);
enum crypto_hash_alg {
CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
};
struct crypto_hash;
/**
* crypto_hash_init - Initialize hash/HMAC function
* @alg: Hash algorithm
* @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
* @key_len: Length of the key in bytes
* Returns: Pointer to hash context to use with other hash functions or %NULL
* on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len);
/**
* crypto_hash_update - Add data to hash calculation
* @ctx: Context pointer from crypto_hash_init()
* @data: Data buffer to add
* @len: Length of the buffer
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
/**
* crypto_hash_finish - Complete hash calculation
* @ctx: Context pointer from crypto_hash_init()
* @hash: Buffer for hash value or %NULL if caller is just freeing the hash
* context
* @len: Pointer to length of the buffer or %NULL if caller is just freeing the
* hash context; on return, this is set to the actual length of the hash value
* Returns: 0 on success, -1 if buffer is too small (len set to needed length),
* or -2 on other failures (including failed crypto_hash_update() operations)
*
* This function calculates the hash value and frees the context buffer that
* was used for hash calculation.
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
enum crypto_cipher_alg {
CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
};
struct crypto_cipher;
/**
* crypto_cipher_init - Initialize block/stream cipher function
* @alg: Cipher algorithm
* @iv: Initialization vector for block ciphers or %NULL for stream ciphers
* @key: Cipher key
* @key_len: Length of key in bytes
* Returns: Pointer to cipher context to use with other cipher functions or
* %NULL on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len);
/**
* crypto_cipher_encrypt - Cipher encrypt
* @ctx: Context pointer from crypto_cipher_init()
* @plain: Plaintext to cipher
* @crypt: Resulting ciphertext
* @len: Length of the plaintext
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx,
const u8 *plain, u8 *crypt, size_t len);
/**
* crypto_cipher_decrypt - Cipher decrypt
* @ctx: Context pointer from crypto_cipher_init()
* @crypt: Ciphertext to decrypt
* @plain: Resulting plaintext
* @len: Length of the cipher text
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx,
const u8 *crypt, u8 *plain, size_t len);
/**
* crypto_cipher_decrypt - Free cipher context
* @ctx: Context pointer from crypto_cipher_init()
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_cipher_deinit(struct crypto_cipher *ctx);
struct crypto_public_key;
struct crypto_private_key;
/**
* crypto_public_key_import - Import an RSA public key
* @key: Key buffer (DER encoded RSA public key)
* @len: Key buffer length in bytes
* Returns: Pointer to the public key or %NULL on failure
*
* This function can just return %NULL if the crypto library supports X.509
* parsing. In that case, crypto_public_key_from_cert() is used to import the
* public key from a certificate.
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
/**
* crypto_private_key_import - Import an RSA private key
* @key: Key buffer (DER encoded RSA private key)
* @len: Key buffer length in bytes
* @passwd: Key encryption password or %NULL if key is not encrypted
* Returns: Pointer to the private key or %NULL on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd);
/**
* crypto_public_key_from_cert - Import an RSA public key from a certificate
* @buf: DER encoded X.509 certificate
* @len: Certificate buffer length in bytes
* Returns: Pointer to public key or %NULL on failure
*
* This function can just return %NULL if the crypto library does not support
* X.509 parsing. In that case, internal code will be used to parse the
* certificate and public key is imported using crypto_public_key_import().
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len);
/**
* crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
* @key: Public key
* @in: Plaintext buffer
* @inlen: Length of plaintext buffer in bytes
* @out: Output buffer for encrypted data
* @outlen: Length of output buffer in bytes; set to used length on success
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_public_key_encrypt_pkcs1_v15(
struct crypto_public_key *key, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
/**
* crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
* @key: Private key
* @in: Encrypted buffer
* @inlen: Length of encrypted buffer in bytes
* @out: Output buffer for encrypted data
* @outlen: Length of output buffer in bytes; set to used length on success
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_private_key_decrypt_pkcs1_v15(
struct crypto_private_key *key, const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
/**
* crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
* @key: Private key from crypto_private_key_import()
* @in: Plaintext buffer
* @inlen: Length of plaintext buffer in bytes
* @out: Output buffer for encrypted (signed) data
* @outlen: Length of output buffer in bytes; set to used length on success
* Returns: 0 on success, -1 on failure
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen);
/**
* crypto_public_key_free - Free public key
* @key: Public key
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_public_key_free(struct crypto_public_key *key);
/**
* crypto_private_key_free - Free private key
* @key: Private key from crypto_private_key_import()
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_private_key_free(struct crypto_private_key *key);
/**
* crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
* @key: Public key
* @crypt: Encrypted signature data (using the private key)
* @crypt_len: Encrypted signature data length
* @plain: Buffer for plaintext (at least crypt_len bytes)
* @plain_len: Plaintext length (max buffer size on input, real len on output);
* Returns: 0 on success, -1 on failure
*/
int __must_check crypto_public_key_decrypt_pkcs1(
struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len);
/**
* crypto_global_init - Initialize crypto wrapper
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_global_init(void);
/**
* crypto_global_deinit - Deinitialize crypto wrapper
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
void crypto_global_deinit(void);
/**
* crypto_mod_exp - Modular exponentiation of large integers
* @base: Base integer (big endian byte array)
* @base_len: Length of base integer in bytes
* @power: Power integer (big endian byte array)
* @power_len: Length of power integer in bytes
* @modulus: Modulus integer (big endian byte array)
* @modulus_len: Length of modulus integer in bytes
* @result: Buffer for the result
* @result_len: Result length (max buffer size on input, real len on output)
* Returns: 0 on success, -1 on failure
*
* This function calculates result = base ^ power mod modulus. modules_len is
* used as the maximum size of modulus buffer. It is set to the used size on
* success.
*
* This function is only used with internal TLSv1 implementation
* (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
* to implement this.
*/
int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len);
/**
* rc4_skip - XOR RC4 stream to given data with skip-stream-start
* @key: RC4 key
* @keylen: RC4 key length
* @skip: number of bytes to skip from the beginning of the RC4 stream
* @data: data to be XOR'ed with RC4 stream
* @data_len: buf length
* Returns: 0 on success, -1 on failure
*
* Generate RC4 pseudo random stream for the given key, skip beginning of the
* stream, and XOR the end result with the data buffer to perform RC4
* encryption/decryption.
*/
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len);
#endif /* CRYPTO_H */

View file

@ -0,0 +1,789 @@
/*
* Crypto wrapper for Microsoft CryptoAPI
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include <windows.h>
#include <wincrypt.h>
#include "common.h"
#include "crypto.h"
#ifndef MS_ENH_RSA_AES_PROV
#ifdef UNICODE
#define MS_ENH_RSA_AES_PROV \
L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
#else
#define MS_ENH_RSA_AES_PROV \
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
#endif
#endif /* MS_ENH_RSA_AES_PROV */
#ifndef CALG_HMAC
#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
#endif
#ifdef __MINGW32_VERSION
/*
* MinGW does not yet include all the needed definitions for CryptoAPI, so
* define here whatever extra is needed.
*/
static BOOL WINAPI
(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
= NULL; /* to be loaded from crypt32.dll */
static int mingw_load_crypto_func(void)
{
HINSTANCE dll;
/* MinGW does not yet have full CryptoAPI support, so load the needed
* function here. */
if (CryptImportPublicKeyInfo)
return 0;
dll = LoadLibrary("crypt32");
if (dll == NULL) {
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
"library");
return -1;
}
CryptImportPublicKeyInfo = GetProcAddress(
dll, "CryptImportPublicKeyInfo");
if (CryptImportPublicKeyInfo == NULL) {
wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
"CryptImportPublicKeyInfo() address from "
"crypt32 library");
return -1;
}
return 0;
}
#else /* __MINGW32_VERSION */
static int mingw_load_crypto_func(void)
{
return 0;
}
#endif /* __MINGW32_VERSION */
static void cryptoapi_report_error(const char *msg)
{
char *s, *pos;
DWORD err = GetLastError();
if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
}
pos = s;
while (*pos) {
if (*pos == '\n' || *pos == '\r') {
*pos = '\0';
break;
}
pos++;
}
wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
LocalFree(s);
}
int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
HCRYPTPROV prov;
HCRYPTHASH hash;
size_t i;
DWORD hlen;
int ret = 0;
if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
cryptoapi_report_error("CryptAcquireContext");
return -1;
}
if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
cryptoapi_report_error("CryptCreateHash");
CryptReleaseContext(prov, 0);
return -1;
}
for (i = 0; i < num_elem; i++) {
if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
cryptoapi_report_error("CryptHashData");
CryptDestroyHash(hash);
CryptReleaseContext(prov, 0);
}
}
hlen = hash_len;
if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
cryptoapi_report_error("CryptGetHashParam");
ret = -1;
}
CryptDestroyHash(hash);
CryptReleaseContext(prov, 0);
return ret;
}
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 next, tmp;
int i;
HCRYPTPROV prov;
HCRYPTKEY ckey;
DWORD dlen;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[8];
} key_blob;
DWORD mode = CRYPT_MODE_ECB;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
key_blob.hdr.aiKeyAlg = CALG_DES;
key_blob.len = 8;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
key_blob.key[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
key_blob.key[i] = next | 1;
if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
"%d", (int) GetLastError());
return;
}
if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
&ckey)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
(int) GetLastError());
CryptReleaseContext(prov, 0);
return;
}
if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
"failed: %d", (int) GetLastError());
CryptDestroyKey(ckey);
CryptReleaseContext(prov, 0);
return;
}
os_memcpy(cypher, clear, 8);
dlen = 8;
if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
(int) GetLastError());
os_memset(cypher, 0, 8);
}
CryptDestroyKey(ckey);
CryptReleaseContext(prov, 0);
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
}
struct aes_context {
HCRYPTPROV prov;
HCRYPTKEY ckey;
};
void * aes_encrypt_init(const u8 *key, size_t len)
{
struct aes_context *akey;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[16];
} key_blob;
DWORD mode = CRYPT_MODE_ECB;
if (len != 16)
return NULL;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
key_blob.hdr.aiKeyAlg = CALG_AES_128;
key_blob.len = len;
os_memcpy(key_blob.key, key, len);
akey = os_zalloc(sizeof(*akey));
if (akey == NULL)
return NULL;
if (!CryptAcquireContext(&akey->prov, NULL,
MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
CRYPT_VERIFYCONTEXT)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
"%d", (int) GetLastError());
os_free(akey);
return NULL;
}
if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
0, 0, &akey->ckey)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
(int) GetLastError());
CryptReleaseContext(akey->prov, 0);
os_free(akey);
return NULL;
}
if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
"failed: %d", (int) GetLastError());
CryptDestroyKey(akey->ckey);
CryptReleaseContext(akey->prov, 0);
os_free(akey);
return NULL;
}
return akey;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
struct aes_context *akey = ctx;
DWORD dlen;
os_memcpy(crypt, plain, 16);
dlen = 16;
if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
(int) GetLastError());
os_memset(crypt, 0, 16);
}
}
void aes_encrypt_deinit(void *ctx)
{
struct aes_context *akey = ctx;
if (akey) {
CryptDestroyKey(akey->ckey);
CryptReleaseContext(akey->prov, 0);
os_free(akey);
}
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
return aes_encrypt_init(key, len);
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
struct aes_context *akey = ctx;
DWORD dlen;
os_memcpy(plain, crypt, 16);
dlen = 16;
if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
(int) GetLastError());
}
}
void aes_decrypt_deinit(void *ctx)
{
aes_encrypt_deinit(ctx);
}
struct crypto_hash {
enum crypto_hash_alg alg;
int error;
HCRYPTPROV prov;
HCRYPTHASH hash;
HCRYPTKEY key;
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
struct crypto_hash *ctx;
ALG_ID calg;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[32];
} key_blob;
os_memset(&key_blob, 0, sizeof(key_blob));
switch (alg) {
case CRYPTO_HASH_ALG_MD5:
calg = CALG_MD5;
break;
case CRYPTO_HASH_ALG_SHA1:
calg = CALG_SHA;
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
case CRYPTO_HASH_ALG_HMAC_SHA1:
calg = CALG_HMAC;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
/*
* Note: RC2 is not really used, but that can be used to
* import HMAC keys of up to 16 byte long.
* CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
* be able to import longer keys (HMAC-SHA1 uses 20-byte key).
*/
key_blob.hdr.aiKeyAlg = CALG_RC2;
key_blob.len = key_len;
if (key_len > sizeof(key_blob.key))
return NULL;
os_memcpy(key_blob.key, key, key_len);
break;
default:
return NULL;
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
cryptoapi_report_error("CryptAcquireContext");
os_free(ctx);
return NULL;
}
if (calg == CALG_HMAC) {
#ifndef CRYPT_IPSEC_HMAC_KEY
#define CRYPT_IPSEC_HMAC_KEY 0x00000100
#endif
if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
&ctx->key)) {
cryptoapi_report_error("CryptImportKey");
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
return NULL;
}
}
if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
cryptoapi_report_error("CryptCreateHash");
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
return NULL;
}
if (calg == CALG_HMAC) {
HMAC_INFO info;
os_memset(&info, 0, sizeof(info));
switch (alg) {
case CRYPTO_HASH_ALG_HMAC_MD5:
info.HashAlgid = CALG_MD5;
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
info.HashAlgid = CALG_SHA;
break;
default:
/* unreachable */
break;
}
if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
0)) {
cryptoapi_report_error("CryptSetHashParam");
CryptDestroyHash(ctx->hash);
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
return NULL;
}
}
return ctx;
}
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL || ctx->error)
return;
if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
cryptoapi_report_error("CryptHashData");
ctx->error = 1;
}
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
int ret = 0;
DWORD hlen;
if (ctx == NULL)
return -2;
if (mac == NULL || len == NULL)
goto done;
if (ctx->error) {
ret = -2;
goto done;
}
hlen = *len;
if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
cryptoapi_report_error("CryptGetHashParam");
ret = -2;
}
*len = hlen;
done:
if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
CryptDestroyKey(ctx->key);
os_free(ctx);
return ret;
}
struct crypto_cipher {
HCRYPTPROV prov;
HCRYPTKEY key;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
struct {
BLOBHEADER hdr;
DWORD len;
BYTE key[32];
} key_blob;
DWORD mode = CRYPT_MODE_CBC;
key_blob.hdr.bType = PLAINTEXTKEYBLOB;
key_blob.hdr.bVersion = CUR_BLOB_VERSION;
key_blob.hdr.reserved = 0;
key_blob.len = key_len;
if (key_len > sizeof(key_blob.key))
return NULL;
os_memcpy(key_blob.key, key, key_len);
switch (alg) {
case CRYPTO_CIPHER_ALG_AES:
if (key_len == 32)
key_blob.hdr.aiKeyAlg = CALG_AES_256;
else if (key_len == 24)
key_blob.hdr.aiKeyAlg = CALG_AES_192;
else
key_blob.hdr.aiKeyAlg = CALG_AES_128;
break;
case CRYPTO_CIPHER_ALG_3DES:
key_blob.hdr.aiKeyAlg = CALG_3DES;
break;
case CRYPTO_CIPHER_ALG_DES:
key_blob.hdr.aiKeyAlg = CALG_DES;
break;
case CRYPTO_CIPHER_ALG_RC2:
key_blob.hdr.aiKeyAlg = CALG_RC2;
break;
case CRYPTO_CIPHER_ALG_RC4:
key_blob.hdr.aiKeyAlg = CALG_RC4;
break;
default:
return NULL;
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
cryptoapi_report_error("CryptAcquireContext");
goto fail1;
}
if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
sizeof(key_blob), 0, 0, &ctx->key)) {
cryptoapi_report_error("CryptImportKey");
goto fail2;
}
if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
goto fail3;
}
if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
goto fail3;
}
return ctx;
fail3:
CryptDestroyKey(ctx->key);
fail2:
CryptReleaseContext(ctx->prov, 0);
fail1:
os_free(ctx);
return NULL;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
DWORD dlen;
os_memcpy(crypt, plain, len);
dlen = len;
if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
cryptoapi_report_error("CryptEncrypt");
os_memset(crypt, 0, len);
return -1;
}
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
DWORD dlen;
os_memcpy(plain, crypt, len);
dlen = len;
if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
cryptoapi_report_error("CryptDecrypt");
return -1;
}
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
CryptDestroyKey(ctx->key);
CryptReleaseContext(ctx->prov, 0);
os_free(ctx);
}
struct crypto_public_key {
HCRYPTPROV prov;
HCRYPTKEY rsa;
};
struct crypto_private_key {
HCRYPTPROV prov;
HCRYPTKEY rsa;
};
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
{
/* Use crypto_public_key_from_cert() instead. */
return NULL;
}
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
{
/* TODO */
return NULL;
}
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len)
{
struct crypto_public_key *pk;
PCCERT_CONTEXT cc;
pk = os_zalloc(sizeof(*pk));
if (pk == NULL)
return NULL;
cc = CertCreateCertificateContext(X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING, buf, len);
if (!cc) {
cryptoapi_report_error("CryptCreateCertificateContext");
os_free(pk);
return NULL;
}
if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
0)) {
cryptoapi_report_error("CryptAcquireContext");
os_free(pk);
CertFreeCertificateContext(cc);
return NULL;
}
if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING,
&cc->pCertInfo->SubjectPublicKeyInfo,
&pk->rsa)) {
cryptoapi_report_error("CryptImportPublicKeyInfo");
CryptReleaseContext(pk->prov, 0);
os_free(pk);
CertFreeCertificateContext(cc);
return NULL;
}
CertFreeCertificateContext(cc);
return pk;
}
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
DWORD clen;
u8 *tmp;
size_t i;
if (*outlen < inlen)
return -1;
tmp = malloc(*outlen);
if (tmp == NULL)
return -1;
os_memcpy(tmp, in, inlen);
clen = inlen;
if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
"public key: %d", (int) GetLastError());
os_free(tmp);
return -1;
}
*outlen = clen;
/* Reverse the output */
for (i = 0; i < *outlen; i++)
out[i] = tmp[*outlen - 1 - i];
os_free(tmp);
return 0;
}
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
/* TODO */
return -1;
}
void crypto_public_key_free(struct crypto_public_key *key)
{
if (key) {
CryptDestroyKey(key->rsa);
CryptReleaseContext(key->prov, 0);
os_free(key);
}
}
void crypto_private_key_free(struct crypto_private_key *key)
{
if (key) {
CryptDestroyKey(key->rsa);
CryptReleaseContext(key->prov, 0);
os_free(key);
}
}
int crypto_global_init(void)
{
return mingw_load_crypto_func();
}
void crypto_global_deinit(void)
{
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
/* TODO */
return -1;
}

View file

@ -0,0 +1,305 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include <gcrypt.h>
#include "common.h"
#include "crypto.h"
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_MD4);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
gcry_md_close(hd);
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
gcry_cipher_hd_t hd;
u8 pkey[8], next, tmp;
int i;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
gcry_cipher_close(hd);
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_MD5);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
gcry_md_close(hd);
return 0;
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
size_t i;
if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
return -1;
for (i = 0; i < num_elem; i++)
gcry_md_write(hd, addr[i], len[i]);
p = gcry_md_read(hd, GCRY_MD_SHA1);
if (p)
memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
gcry_md_close(hd);
return 0;
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR) {
printf("cipher open failed\n");
return NULL;
}
if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
printf("setkey failed\n");
gcry_cipher_close(hd);
return NULL;
}
return hd;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
}
void aes_encrypt_deinit(void *ctx)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
gcry_cipher_hd_t hd;
if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
GPG_ERR_NO_ERROR)
return NULL;
if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(hd);
return NULL;
}
return hd;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
}
void aes_decrypt_deinit(void *ctx)
{
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL,
bn_result = NULL;
int ret = -1;
if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) !=
GPG_ERR_NO_ERROR ||
gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) !=
GPG_ERR_NO_ERROR ||
gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len,
NULL) != GPG_ERR_NO_ERROR)
goto error;
bn_result = gcry_mpi_new(modulus_len * 8);
gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus);
if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len,
bn_result) != GPG_ERR_NO_ERROR)
goto error;
ret = 0;
error:
gcry_mpi_release(bn_base);
gcry_mpi_release(bn_exp);
gcry_mpi_release(bn_modulus);
gcry_mpi_release(bn_result);
return ret;
}
struct crypto_cipher {
gcry_cipher_hd_t enc;
gcry_cipher_hd_t dec;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
gcry_error_t res;
enum gcry_cipher_algos a;
int ivlen;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
switch (alg) {
case CRYPTO_CIPHER_ALG_RC4:
a = GCRY_CIPHER_ARCFOUR;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM,
0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0);
break;
case CRYPTO_CIPHER_ALG_AES:
if (key_len == 24)
a = GCRY_CIPHER_AES192;
else if (key_len == 32)
a = GCRY_CIPHER_AES256;
else
a = GCRY_CIPHER_AES;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
case CRYPTO_CIPHER_ALG_3DES:
a = GCRY_CIPHER_3DES;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
case CRYPTO_CIPHER_ALG_DES:
a = GCRY_CIPHER_DES;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
case CRYPTO_CIPHER_ALG_RC2:
if (key_len == 5)
a = GCRY_CIPHER_RFC2268_40;
else
a = GCRY_CIPHER_RFC2268_128;
res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
break;
default:
os_free(ctx);
return NULL;
}
if (res != GPG_ERR_NO_ERROR) {
os_free(ctx);
return NULL;
}
if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR ||
gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(ctx->enc);
gcry_cipher_close(ctx->dec);
os_free(ctx);
return NULL;
}
ivlen = gcry_cipher_get_algo_blklen(a);
if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR ||
gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) {
gcry_cipher_close(ctx->enc);
gcry_cipher_close(ctx->dec);
os_free(ctx);
return NULL;
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) !=
GPG_ERR_NO_ERROR)
return -1;
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) !=
GPG_ERR_NO_ERROR)
return -1;
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
gcry_cipher_close(ctx->enc);
gcry_cipher_close(ctx->dec);
os_free(ctx);
}

View file

@ -0,0 +1,256 @@
/*
* Crypto wrapper for internal crypto implementation - Cipher wrappers
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "aes.h"
#include "des_i.h"
struct crypto_cipher {
enum crypto_cipher_alg alg;
union {
struct {
size_t used_bytes;
u8 key[16];
size_t keylen;
} rc4;
struct {
u8 cbc[32];
size_t block_size;
void *ctx_enc;
void *ctx_dec;
} aes;
struct {
struct des3_key_s key;
u8 cbc[8];
} des3;
struct {
u32 ek[32];
u32 dk[32];
u8 cbc[8];
} des;
} u;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
switch (alg) {
case CRYPTO_CIPHER_ALG_RC4:
if (key_len > sizeof(ctx->u.rc4.key)) {
os_free(ctx);
return NULL;
}
ctx->u.rc4.keylen = key_len;
os_memcpy(ctx->u.rc4.key, key, key_len);
break;
case CRYPTO_CIPHER_ALG_AES:
if (key_len > sizeof(ctx->u.aes.cbc)) {
os_free(ctx);
return NULL;
}
ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
if (ctx->u.aes.ctx_enc == NULL) {
os_free(ctx);
return NULL;
}
ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
if (ctx->u.aes.ctx_dec == NULL) {
aes_encrypt_deinit(ctx->u.aes.ctx_enc);
os_free(ctx);
return NULL;
}
ctx->u.aes.block_size = key_len;
os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size);
break;
case CRYPTO_CIPHER_ALG_3DES:
if (key_len != 24) {
os_free(ctx);
return NULL;
}
des3_key_setup(key, &ctx->u.des3.key);
os_memcpy(ctx->u.des3.cbc, iv, 8);
break;
case CRYPTO_CIPHER_ALG_DES:
if (key_len != 8) {
os_free(ctx);
return NULL;
}
des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
os_memcpy(ctx->u.des.cbc, iv, 8);
break;
default:
os_free(ctx);
return NULL;
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
size_t i, j, blocks;
switch (ctx->alg) {
case CRYPTO_CIPHER_ALG_RC4:
if (plain != crypt)
os_memcpy(crypt, plain, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, crypt, len);
ctx->u.rc4.used_bytes += len;
break;
case CRYPTO_CIPHER_ALG_AES:
if (len % ctx->u.aes.block_size)
return -1;
blocks = len / ctx->u.aes.block_size;
for (i = 0; i < blocks; i++) {
for (j = 0; j < ctx->u.aes.block_size; j++)
ctx->u.aes.cbc[j] ^= plain[j];
aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
ctx->u.aes.cbc);
os_memcpy(crypt, ctx->u.aes.cbc,
ctx->u.aes.block_size);
plain += ctx->u.aes.block_size;
crypt += ctx->u.aes.block_size;
}
break;
case CRYPTO_CIPHER_ALG_3DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
for (j = 0; j < 8; j++)
ctx->u.des3.cbc[j] ^= plain[j];
des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
ctx->u.des3.cbc);
os_memcpy(crypt, ctx->u.des3.cbc, 8);
plain += 8;
crypt += 8;
}
break;
case CRYPTO_CIPHER_ALG_DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
for (j = 0; j < 8; j++)
ctx->u.des3.cbc[j] ^= plain[j];
des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
ctx->u.des.cbc);
os_memcpy(crypt, ctx->u.des.cbc, 8);
plain += 8;
crypt += 8;
}
break;
default:
return -1;
}
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
size_t i, j, blocks;
u8 tmp[32];
switch (ctx->alg) {
case CRYPTO_CIPHER_ALG_RC4:
if (plain != crypt)
os_memcpy(plain, crypt, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, plain, len);
ctx->u.rc4.used_bytes += len;
break;
case CRYPTO_CIPHER_ALG_AES:
if (len % ctx->u.aes.block_size)
return -1;
blocks = len / ctx->u.aes.block_size;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, crypt, ctx->u.aes.block_size);
aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
for (j = 0; j < ctx->u.aes.block_size; j++)
plain[j] ^= ctx->u.aes.cbc[j];
os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size);
plain += ctx->u.aes.block_size;
crypt += ctx->u.aes.block_size;
}
break;
case CRYPTO_CIPHER_ALG_3DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, crypt, 8);
des3_decrypt(crypt, &ctx->u.des3.key, plain);
for (j = 0; j < 8; j++)
plain[j] ^= ctx->u.des3.cbc[j];
os_memcpy(ctx->u.des3.cbc, tmp, 8);
plain += 8;
crypt += 8;
}
break;
case CRYPTO_CIPHER_ALG_DES:
if (len % 8)
return -1;
blocks = len / 8;
for (i = 0; i < blocks; i++) {
os_memcpy(tmp, crypt, 8);
des_block_decrypt(crypt, ctx->u.des.dk, plain);
for (j = 0; j < 8; j++)
plain[j] ^= ctx->u.des.cbc[j];
os_memcpy(ctx->u.des.cbc, tmp, 8);
plain += 8;
crypt += 8;
}
break;
default:
return -1;
}
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
switch (ctx->alg) {
case CRYPTO_CIPHER_ALG_AES:
aes_encrypt_deinit(ctx->u.aes.ctx_enc);
aes_decrypt_deinit(ctx->u.aes.ctx_dec);
break;
case CRYPTO_CIPHER_ALG_3DES:
break;
default:
break;
}
os_free(ctx);
}

View file

@ -0,0 +1,55 @@
/*
* Crypto wrapper for internal crypto implementation - modexp
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "tls/bignum.h"
#include "crypto.h"
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
int ret = -1;
bn_base = bignum_init();
bn_exp = bignum_init();
bn_modulus = bignum_init();
bn_result = bignum_init();
if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
bn_result == NULL)
goto error;
if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
goto error;
if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
goto error;
ret = bignum_get_unsigned_bin(bn_result, result, result_len);
error:
bignum_deinit(bn_base);
bignum_deinit(bn_exp);
bignum_deinit(bn_modulus);
bignum_deinit(bn_result);
return ret;
}

View file

@ -0,0 +1,115 @@
/*
* Crypto wrapper for internal crypto implementation - RSA parts
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "tls/rsa.h"
#include "tls/bignum.h"
#include "tls/pkcs1.h"
#include "tls/pkcs8.h"
/* Dummy structures; these are just typecast to struct crypto_rsa_key */
struct crypto_public_key;
struct crypto_private_key;
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
{
return (struct crypto_public_key *)
crypto_rsa_import_public_key(key, len);
}
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
{
struct crypto_private_key *res;
/* First, check for possible PKCS #8 encoding */
res = pkcs8_key_import(key, len);
if (res)
return res;
if (passwd) {
/* Try to parse as encrypted PKCS #8 */
res = pkcs8_enc_key_import(key, len, passwd);
if (res)
return res;
}
/* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
"key");
return (struct crypto_private_key *)
crypto_rsa_import_private_key(key, len);
}
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len)
{
/* No X.509 support in crypto_internal.c */
return NULL;
}
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return pkcs1_encrypt(2, (struct crypto_rsa_key *) key,
0, in, inlen, out, outlen);
}
int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key,
in, inlen, out, outlen);
}
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return pkcs1_encrypt(1, (struct crypto_rsa_key *) key,
1, in, inlen, out, outlen);
}
void crypto_public_key_free(struct crypto_public_key *key)
{
crypto_rsa_free((struct crypto_rsa_key *) key);
}
void crypto_private_key_free(struct crypto_private_key *key)
{
crypto_rsa_free((struct crypto_rsa_key *) key);
}
int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len)
{
return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key,
crypt, crypt_len, plain, plain_len);
}

View file

@ -0,0 +1,205 @@
/*
* Crypto wrapper for internal crypto implementation
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "sha1_i.h"
#include "md5_i.h"
struct crypto_hash {
enum crypto_hash_alg alg;
union {
struct MD5Context md5;
struct SHA1Context sha1;
} u;
u8 key[64];
size_t key_len;
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
struct crypto_hash *ctx;
u8 k_pad[64];
u8 tk[20];
size_t i;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
switch (alg) {
case CRYPTO_HASH_ALG_MD5:
MD5Init(&ctx->u.md5);
break;
case CRYPTO_HASH_ALG_SHA1:
SHA1Init(&ctx->u.sha1);
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
if (key_len > sizeof(k_pad)) {
MD5Init(&ctx->u.md5);
MD5Update(&ctx->u.md5, key, key_len);
MD5Final(tk, &ctx->u.md5);
key = tk;
key_len = 16;
}
os_memcpy(ctx->key, key, key_len);
ctx->key_len = key_len;
os_memcpy(k_pad, key, key_len);
os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x36;
MD5Init(&ctx->u.md5);
MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (key_len > sizeof(k_pad)) {
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, key, key_len);
SHA1Final(tk, &ctx->u.sha1);
key = tk;
key_len = 20;
}
os_memcpy(ctx->key, key, key_len);
ctx->key_len = key_len;
os_memcpy(k_pad, key, key_len);
os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x36;
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
break;
default:
os_free(ctx);
return NULL;
}
return ctx;
}
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL)
return;
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
case CRYPTO_HASH_ALG_HMAC_MD5:
MD5Update(&ctx->u.md5, data, len);
break;
case CRYPTO_HASH_ALG_SHA1:
case CRYPTO_HASH_ALG_HMAC_SHA1:
SHA1Update(&ctx->u.sha1, data, len);
break;
}
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
u8 k_pad[64];
size_t i;
if (ctx == NULL)
return -2;
if (mac == NULL || len == NULL) {
os_free(ctx);
return 0;
}
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
*len = 16;
MD5Final(mac, &ctx->u.md5);
break;
case CRYPTO_HASH_ALG_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
*len = 20;
SHA1Final(mac, &ctx->u.sha1);
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
*len = 16;
MD5Final(mac, &ctx->u.md5);
os_memcpy(k_pad, ctx->key, ctx->key_len);
os_memset(k_pad + ctx->key_len, 0,
sizeof(k_pad) - ctx->key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x5c;
MD5Init(&ctx->u.md5);
MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
MD5Update(&ctx->u.md5, mac, 16);
MD5Final(mac, &ctx->u.md5);
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
*len = 20;
SHA1Final(mac, &ctx->u.sha1);
os_memcpy(k_pad, ctx->key, ctx->key_len);
os_memset(k_pad + ctx->key_len, 0,
sizeof(k_pad) - ctx->key_len);
for (i = 0; i < sizeof(k_pad); i++)
k_pad[i] ^= 0x5c;
SHA1Init(&ctx->u.sha1);
SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
SHA1Update(&ctx->u.sha1, mac, 20);
SHA1Final(mac, &ctx->u.sha1);
break;
}
os_free(ctx);
return 0;
}
int crypto_global_init(void)
{
return 0;
}
void crypto_global_deinit(void)
{
}

View file

@ -0,0 +1,732 @@
/*
* WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include <tomcrypt.h>
#include "common.h"
#include "crypto.h"
#ifndef mp_init_multi
#define mp_init_multi ltc_init_multi
#define mp_clear_multi ltc_deinit_multi
#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
#endif
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
hash_state md;
size_t i;
md4_init(&md);
for (i = 0; i < num_elem; i++)
md4_process(&md, addr[i], len[i]);
md4_done(&md, mac);
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
symmetric_key skey;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
des_setup(pkey, 8, 0, &skey);
des_ecb_encrypt(clear, cypher, &skey);
des_done(&skey);
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
hash_state md;
size_t i;
md5_init(&md);
for (i = 0; i < num_elem; i++)
md5_process(&md, addr[i], len[i]);
md5_done(&md, mac);
return 0;
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
hash_state md;
size_t i;
sha1_init(&md);
for (i = 0; i < num_elem; i++)
sha1_process(&md, addr[i], len[i]);
sha1_done(&md, mac);
return 0;
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
symmetric_key *skey;
skey = os_malloc(sizeof(*skey));
if (skey == NULL)
return NULL;
if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
os_free(skey);
return NULL;
}
return skey;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
symmetric_key *skey = ctx;
aes_ecb_encrypt(plain, crypt, skey);
}
void aes_encrypt_deinit(void *ctx)
{
symmetric_key *skey = ctx;
aes_done(skey);
os_free(skey);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
symmetric_key *skey;
skey = os_malloc(sizeof(*skey));
if (skey == NULL)
return NULL;
if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
os_free(skey);
return NULL;
}
return skey;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
symmetric_key *skey = ctx;
aes_ecb_encrypt(plain, (u8 *) crypt, skey);
}
void aes_decrypt_deinit(void *ctx)
{
symmetric_key *skey = ctx;
aes_done(skey);
os_free(skey);
}
struct crypto_hash {
enum crypto_hash_alg alg;
int error;
union {
hash_state md;
hmac_state hmac;
} u;
};
struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
size_t key_len)
{
struct crypto_hash *ctx;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
ctx->alg = alg;
switch (alg) {
case CRYPTO_HASH_ALG_MD5:
if (md5_init(&ctx->u.md) != CRYPT_OK)
goto fail;
break;
case CRYPTO_HASH_ALG_SHA1:
if (sha1_init(&ctx->u.md) != CRYPT_OK)
goto fail;
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
CRYPT_OK)
goto fail;
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
CRYPT_OK)
goto fail;
break;
default:
goto fail;
}
return ctx;
fail:
os_free(ctx);
return NULL;
}
void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL || ctx->error)
return;
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
break;
case CRYPTO_HASH_ALG_SHA1:
ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
break;
case CRYPTO_HASH_ALG_HMAC_MD5:
case CRYPTO_HASH_ALG_HMAC_SHA1:
ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
break;
}
}
int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
{
int ret = 0;
unsigned long clen;
if (ctx == NULL)
return -2;
if (mac == NULL || len == NULL) {
os_free(ctx);
return 0;
}
if (ctx->error) {
os_free(ctx);
return -2;
}
switch (ctx->alg) {
case CRYPTO_HASH_ALG_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
*len = 16;
if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
ret = -2;
break;
case CRYPTO_HASH_ALG_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
*len = 20;
if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
ret = -2;
break;
case CRYPTO_HASH_ALG_HMAC_SHA1:
if (*len < 20) {
*len = 20;
os_free(ctx);
return -1;
}
/* continue */
case CRYPTO_HASH_ALG_HMAC_MD5:
if (*len < 16) {
*len = 16;
os_free(ctx);
return -1;
}
clen = *len;
if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
os_free(ctx);
return -1;
}
*len = clen;
break;
default:
ret = -2;
break;
}
os_free(ctx);
return ret;
}
struct crypto_cipher {
int rc4;
union {
symmetric_CBC cbc;
struct {
size_t used_bytes;
u8 key[16];
size_t keylen;
} rc4;
} u;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
int idx, res, rc4 = 0;
switch (alg) {
case CRYPTO_CIPHER_ALG_AES:
idx = find_cipher("aes");
break;
case CRYPTO_CIPHER_ALG_3DES:
idx = find_cipher("3des");
break;
case CRYPTO_CIPHER_ALG_DES:
idx = find_cipher("des");
break;
case CRYPTO_CIPHER_ALG_RC2:
idx = find_cipher("rc2");
break;
case CRYPTO_CIPHER_ALG_RC4:
idx = -1;
rc4 = 1;
break;
default:
return NULL;
}
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
if (rc4) {
ctx->rc4 = 1;
if (key_len > sizeof(ctx->u.rc4.key)) {
os_free(ctx);
return NULL;
}
ctx->u.rc4.keylen = key_len;
os_memcpy(ctx->u.rc4.key, key, key_len);
} else {
res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
"failed: %s", error_to_string(res));
os_free(ctx);
return NULL;
}
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
int res;
if (ctx->rc4) {
if (plain != crypt)
os_memcpy(crypt, plain, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, crypt, len);
ctx->u.rc4.used_bytes += len;
return 0;
}
res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
"failed: %s", error_to_string(res));
return -1;
}
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
int res;
if (ctx->rc4) {
if (plain != crypt)
os_memcpy(plain, crypt, len);
rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
ctx->u.rc4.used_bytes, plain, len);
ctx->u.rc4.used_bytes += len;
return 0;
}
res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
"failed: %s", error_to_string(res));
return -1;
}
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
if (!ctx->rc4)
cbc_done(&ctx->u.cbc);
os_free(ctx);
}
struct crypto_public_key {
rsa_key rsa;
};
struct crypto_private_key {
rsa_key rsa;
};
struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
{
int res;
struct crypto_public_key *pk;
pk = os_zalloc(sizeof(*pk));
if (pk == NULL)
return NULL;
res = rsa_import(key, len, &pk->rsa);
if (res != CRYPT_OK) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
"public key (res=%d '%s')",
res, error_to_string(res));
os_free(pk);
return NULL;
}
if (pk->rsa.type != PK_PUBLIC) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
"correct type");
rsa_free(&pk->rsa);
os_free(pk);
return NULL;
}
return pk;
}
struct crypto_private_key * crypto_private_key_import(const u8 *key,
size_t len,
const char *passwd)
{
int res;
struct crypto_private_key *pk;
pk = os_zalloc(sizeof(*pk));
if (pk == NULL)
return NULL;
res = rsa_import(key, len, &pk->rsa);
if (res != CRYPT_OK) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
"private key (res=%d '%s')",
res, error_to_string(res));
os_free(pk);
return NULL;
}
if (pk->rsa.type != PK_PRIVATE) {
wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
"correct type");
rsa_free(&pk->rsa);
os_free(pk);
return NULL;
}
return pk;
}
struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
size_t len)
{
/* No X.509 support in LibTomCrypt */
return NULL;
}
static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
size_t ps_len;
u8 *pos;
/*
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
* BT = 00 or 01 for private-key operation; 02 for public-key operation
* PS = k-3-||D||; at least eight octets
* (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
* k = length of modulus in octets (modlen)
*/
if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
"lengths (modlen=%lu outlen=%lu inlen=%lu)",
__func__, (unsigned long) modlen,
(unsigned long) *outlen,
(unsigned long) inlen);
return -1;
}
pos = out;
*pos++ = 0x00;
*pos++ = block_type; /* BT */
ps_len = modlen - inlen - 3;
switch (block_type) {
case 0:
os_memset(pos, 0x00, ps_len);
pos += ps_len;
break;
case 1:
os_memset(pos, 0xff, ps_len);
pos += ps_len;
break;
case 2:
if (os_get_random(pos, ps_len) < 0) {
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
"random data for PS", __func__);
return -1;
}
while (ps_len--) {
if (*pos == 0x00)
*pos = 0x01;
pos++;
}
break;
default:
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
"%d", __func__, block_type);
return -1;
}
*pos++ = 0x00;
os_memcpy(pos, in, inlen); /* D */
return 0;
}
static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
unsigned long len, modlen;
int res;
modlen = mp_unsigned_bin_size(key->N);
if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
out, outlen) < 0)
return -1;
len = *outlen;
res = rsa_exptmod(out, modlen, out, &len, key_type, key);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
error_to_string(res));
return -1;
}
*outlen = len;
return 0;
}
int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
out, outlen);
}
int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
const u8 *in, size_t inlen,
u8 *out, size_t *outlen)
{
return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
out, outlen);
}
void crypto_public_key_free(struct crypto_public_key *key)
{
if (key) {
rsa_free(&key->rsa);
os_free(key);
}
}
void crypto_private_key_free(struct crypto_private_key *key)
{
if (key) {
rsa_free(&key->rsa);
os_free(key);
}
}
int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
const u8 *crypt, size_t crypt_len,
u8 *plain, size_t *plain_len)
{
int res;
unsigned long len;
u8 *pos;
len = *plain_len;
res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
&key->rsa);
if (res != CRYPT_OK) {
wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
error_to_string(res));
return -1;
}
/*
* PKCS #1 v1.5, 8.1:
*
* EB = 00 || BT || PS || 00 || D
* BT = 01
* PS = k-3-||D|| times FF
* k = length of modulus in octets
*/
if (len < 3 + 8 + 16 /* min hash len */ ||
plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure");
return -1;
}
pos = plain + 3;
while (pos < plain + len && *pos == 0xff)
pos++;
if (pos - plain - 2 < 8) {
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
"padding");
return -1;
}
if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
"structure (2)");
return -1;
}
pos++;
len -= pos - plain;
/* Strip PKCS #1 header */
os_memmove(plain, pos, len);
*plain_len = len;
return 0;
}
int crypto_global_init(void)
{
ltc_mp = tfm_desc;
/* TODO: only register algorithms that are really needed */
if (register_hash(&md4_desc) < 0 ||
register_hash(&md5_desc) < 0 ||
register_hash(&sha1_desc) < 0 ||
register_cipher(&aes_desc) < 0 ||
register_cipher(&des_desc) < 0 ||
register_cipher(&des3_desc) < 0) {
wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
"hash/cipher functions");
return -1;
}
return 0;
}
void crypto_global_deinit(void)
{
}
#ifdef CONFIG_MODEXP
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
void *b, *p, *m, *r;
if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
return -1;
if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
goto fail;
if (mp_exptmod(b, p, m, r) != CRYPT_OK)
goto fail;
*result_len = mp_unsigned_bin_size(r);
if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
goto fail;
mp_clear_multi(b, p, m, r, NULL);
return 0;
fail:
mp_clear_multi(b, p, m, r, NULL);
return -1;
}
#endif /* CONFIG_MODEXP */

View file

@ -0,0 +1,29 @@
/*
* WPA Supplicant / Empty template functions for crypto wrapper
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
}

View file

@ -0,0 +1,213 @@
/*
* Crypto wrapper functions for NSS
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include <nspr/prtypes.h>
#include <nspr/plarenas.h>
#include <nspr/plhash.h>
#include <nspr/prtime.h>
#include <nspr/prinrval.h>
#include <nspr/prclist.h>
#include <nspr/prlock.h>
#include <nss/sechash.h>
#include <nss/pk11pub.h>
#include "common.h"
#include "crypto.h"
static int nss_hash(HASH_HashType type, unsigned int max_res_len,
size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
HASHContext *ctx;
size_t i;
unsigned int reslen;
ctx = HASH_Create(type);
if (ctx == NULL)
return -1;
HASH_Begin(ctx);
for (i = 0; i < num_elem; i++)
HASH_Update(ctx, addr[i], len[i]);
HASH_End(ctx, mac, &reslen, max_res_len);
HASH_Destroy(ctx);
return 0;
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
PK11Context *ctx = NULL;
PK11SlotInfo *slot;
SECItem *param = NULL;
PK11SymKey *symkey = NULL;
SECItem item;
int olen;
u8 pkey[8], next, tmp;
int i;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
if (slot == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
goto out;
}
item.type = siBuffer;
item.data = pkey;
item.len = 8;
symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
CKA_ENCRYPT, &item, NULL);
if (symkey == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
goto out;
}
param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
if (param == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
goto out;
}
ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
symkey, param);
if (ctx == NULL) {
wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
"CKM_DES_ECB) failed");
goto out;
}
if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
SECSuccess) {
wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
goto out;
}
out:
if (ctx)
PK11_DestroyContext(ctx, PR_TRUE);
if (symkey)
PK11_FreeSymKey(symkey);
if (param)
SECITEM_FreeItem(param, PR_TRUE);
}
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
return -1;
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
}
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
}
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
return NULL;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
}
void aes_encrypt_deinit(void *ctx)
{
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
return NULL;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
}
void aes_decrypt_deinit(void *ctx)
{
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
return -1;
}
struct crypto_cipher {
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
return NULL;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
return -1;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
return -1;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
}

View file

@ -0,0 +1,505 @@
/*
* WPA Supplicant / wrapper functions for libcrypto
* Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include <openssl/opensslv.h>
#include <openssl/err.h>
#include <openssl/des.h>
#include <openssl/aes.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/dh.h>
#include "common.h"
#include "wpabuf.h"
#include "dh_group5.h"
#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000
#define DES_key_schedule des_key_schedule
#define DES_cblock des_cblock
#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
#define DES_ecb_encrypt(input, output, ks, enc) \
des_ecb_encrypt((input), (output), *(ks), (enc))
#endif /* openssl < 0.9.7 */
static BIGNUM * get_group5_prime(void)
{
#if OPENSSL_VERSION_NUMBER < 0x00908000
static const unsigned char RFC3526_PRIME_1536[] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
};
return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
#else /* openssl < 0.9.8 */
return get_rfc3526_prime_1536(NULL);
#endif /* openssl < 0.9.8 */
}
#if OPENSSL_VERSION_NUMBER < 0x00908000
#ifndef OPENSSL_NO_SHA256
#ifndef OPENSSL_FIPS
#define NO_SHA256_WRAPPER
#endif
#endif
#endif /* openssl < 0.9.8 */
#ifdef OPENSSL_NO_SHA256
#define NO_SHA256_WRAPPER
#endif
static int openssl_digest_vector(const EVP_MD *type, int non_fips,
size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac)
{
EVP_MD_CTX ctx;
size_t i;
unsigned int mac_len;
EVP_MD_CTX_init(&ctx);
#ifdef CONFIG_FIPS
#ifdef OPENSSL_FIPS
if (non_fips)
EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
#endif /* OPENSSL_FIPS */
#endif /* CONFIG_FIPS */
if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
for (i = 0; i < num_elem; i++) {
if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
"failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
}
if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return -1;
}
return 0;
}
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
}
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
DES_key_schedule ks;
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
DES_set_key(&pkey, &ks);
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
}
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
#ifdef OPENSSL_NO_RC4
return -1;
#else /* OPENSSL_NO_RC4 */
EVP_CIPHER_CTX ctx;
int outl;
int res = -1;
unsigned char skip_buf[16];
EVP_CIPHER_CTX_init(&ctx);
if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
!EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
!EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
!EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
goto out;
while (skip >= sizeof(skip_buf)) {
size_t len = skip;
if (len > sizeof(skip_buf))
len = sizeof(skip_buf);
if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
goto out;
skip -= len;
}
if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
res = 0;
out:
EVP_CIPHER_CTX_cleanup(&ctx);
return res;
#endif /* OPENSSL_NO_RC4 */
}
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
}
#ifdef CONFIG_FIPS
int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
}
#endif /* CONFIG_FIPS */
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
}
#ifndef NO_SHA256_WRAPPER
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
mac);
}
#endif /* NO_SHA256_WRAPPER */
void * aes_encrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
os_free(ak);
return NULL;
}
return ak;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
AES_encrypt(plain, crypt, ctx);
}
void aes_encrypt_deinit(void *ctx)
{
os_free(ctx);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
os_free(ak);
return NULL;
}
return ak;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
AES_decrypt(crypt, plain, ctx);
}
void aes_decrypt_deinit(void *ctx)
{
os_free(ctx);
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
const u8 *modulus, size_t modulus_len,
u8 *result, size_t *result_len)
{
BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
int ret = -1;
BN_CTX *ctx;
ctx = BN_CTX_new();
if (ctx == NULL)
return -1;
bn_base = BN_bin2bn(base, base_len, NULL);
bn_exp = BN_bin2bn(power, power_len, NULL);
bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
bn_result = BN_new();
if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
bn_result == NULL)
goto error;
if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
goto error;
*result_len = BN_bn2bin(bn_result, result);
ret = 0;
error:
BN_free(bn_base);
BN_free(bn_exp);
BN_free(bn_modulus);
BN_free(bn_result);
BN_CTX_free(ctx);
return ret;
}
struct crypto_cipher {
EVP_CIPHER_CTX enc;
EVP_CIPHER_CTX dec;
};
struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
const u8 *iv, const u8 *key,
size_t key_len)
{
struct crypto_cipher *ctx;
const EVP_CIPHER *cipher;
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
switch (alg) {
#ifndef OPENSSL_NO_RC4
case CRYPTO_CIPHER_ALG_RC4:
cipher = EVP_rc4();
break;
#endif /* OPENSSL_NO_RC4 */
#ifndef OPENSSL_NO_AES
case CRYPTO_CIPHER_ALG_AES:
switch (key_len) {
case 16:
cipher = EVP_aes_128_cbc();
break;
case 24:
cipher = EVP_aes_192_cbc();
break;
case 32:
cipher = EVP_aes_256_cbc();
break;
default:
os_free(ctx);
return NULL;
}
break;
#endif /* OPENSSL_NO_AES */
#ifndef OPENSSL_NO_DES
case CRYPTO_CIPHER_ALG_3DES:
cipher = EVP_des_ede3_cbc();
break;
case CRYPTO_CIPHER_ALG_DES:
cipher = EVP_des_cbc();
break;
#endif /* OPENSSL_NO_DES */
#ifndef OPENSSL_NO_RC2
case CRYPTO_CIPHER_ALG_RC2:
cipher = EVP_rc2_ecb();
break;
#endif /* OPENSSL_NO_RC2 */
default:
os_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_init(&ctx->enc);
EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
!EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
!EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
EVP_CIPHER_CTX_cleanup(&ctx->enc);
os_free(ctx);
return NULL;
}
EVP_CIPHER_CTX_init(&ctx->dec);
EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
!EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
!EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
EVP_CIPHER_CTX_cleanup(&ctx->enc);
EVP_CIPHER_CTX_cleanup(&ctx->dec);
os_free(ctx);
return NULL;
}
return ctx;
}
int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
u8 *crypt, size_t len)
{
int outl;
if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
return -1;
return 0;
}
int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
u8 *plain, size_t len)
{
int outl;
outl = len;
if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
return -1;
return 0;
}
void crypto_cipher_deinit(struct crypto_cipher *ctx)
{
EVP_CIPHER_CTX_cleanup(&ctx->enc);
EVP_CIPHER_CTX_cleanup(&ctx->dec);
os_free(ctx);
}
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
DH *dh;
struct wpabuf *pubkey = NULL, *privkey = NULL;
size_t publen, privlen;
*priv = NULL;
*publ = NULL;
dh = DH_new();
if (dh == NULL)
return NULL;
dh->g = BN_new();
if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
goto err;
dh->p = get_group5_prime();
if (dh->p == NULL)
goto err;
if (DH_generate_key(dh) != 1)
goto err;
publen = BN_num_bytes(dh->pub_key);
pubkey = wpabuf_alloc(publen);
if (pubkey == NULL)
goto err;
privlen = BN_num_bytes(dh->priv_key);
privkey = wpabuf_alloc(privlen);
if (privkey == NULL)
goto err;
BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
*priv = privkey;
*publ = pubkey;
return dh;
err:
wpabuf_free(pubkey);
wpabuf_free(privkey);
DH_free(dh);
return NULL;
}
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
BIGNUM *pub_key;
struct wpabuf *res = NULL;
size_t rlen;
DH *dh = ctx;
int keylen;
if (ctx == NULL)
return NULL;
pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
NULL);
if (pub_key == NULL)
return NULL;
rlen = DH_size(dh);
res = wpabuf_alloc(rlen);
if (res == NULL)
goto err;
keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
if (keylen < 0)
goto err;
wpabuf_put(res, keylen);
BN_free(pub_key);
return res;
err:
BN_free(pub_key);
wpabuf_free(res);
return NULL;
}
void dh5_free(void *ctx)
{
DH *dh;
if (ctx == NULL)
return;
dh = ctx;
DH_free(dh);
}

View file

@ -0,0 +1,499 @@
/*
* DES and 3DES-EDE ciphers
*
* Modifications to LibTomCrypt implementation:
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "crypto.h"
#include "des_i.h"
/*
* This implementation is based on a DES implementation included in
* LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
* coding style.
*/
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
* Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
*/
/**
DES code submitted by Dobes Vandermeer
*/
#define ROLc(x, y) \
((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
(((unsigned long) (x) & 0xFFFFFFFFUL) >> \
(unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
#define RORc(x, y) \
(((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
(unsigned long) ((y) & 31)) | \
((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
0xFFFFFFFFUL)
static const u32 bytebit[8] =
{
0200, 0100, 040, 020, 010, 04, 02, 01
};
static const u32 bigbyte[24] =
{
0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL,
0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL,
0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
0x800UL, 0x400UL, 0x200UL, 0x100UL,
0x80UL, 0x40UL, 0x20UL, 0x10UL,
0x8UL, 0x4UL, 0x2UL, 0x1L
};
/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
static const u8 pc1[56] = {
56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
};
static const u8 totrot[16] = {
1, 2, 4, 6,
8, 10, 12, 14,
15, 17, 19, 21,
23, 25, 27, 28
};
static const u8 pc2[48] = {
13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
};
static const u32 SP1[64] =
{
0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
};
static const u32 SP2[64] =
{
0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
};
static const u32 SP3[64] =
{
0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
};
static const u32 SP4[64] =
{
0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
};
static const u32 SP5[64] =
{
0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
};
static const u32 SP6[64] =
{
0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
};
static const u32 SP7[64] =
{
0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
};
static const u32 SP8[64] =
{
0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
};
static void cookey(const u32 *raw1, u32 *keyout)
{
u32 *cook;
const u32 *raw0;
u32 dough[32];
int i;
cook = dough;
for (i = 0; i < 16; i++, raw1++) {
raw0 = raw1++;
*cook = (*raw0 & 0x00fc0000L) << 6;
*cook |= (*raw0 & 0x00000fc0L) << 10;
*cook |= (*raw1 & 0x00fc0000L) >> 10;
*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
*cook = (*raw0 & 0x0003f000L) << 12;
*cook |= (*raw0 & 0x0000003fL) << 16;
*cook |= (*raw1 & 0x0003f000L) >> 4;
*cook++ |= (*raw1 & 0x0000003fL);
}
os_memcpy(keyout, dough, sizeof(dough));
}
static void deskey(const u8 *key, int decrypt, u32 *keyout)
{
u32 i, j, l, m, n, kn[32];
u8 pc1m[56], pcr[56];
for (j = 0; j < 56; j++) {
l = (u32) pc1[j];
m = l & 7;
pc1m[j] = (u8)
((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
}
for (i = 0; i < 16; i++) {
if (decrypt)
m = (15 - i) << 1;
else
m = i << 1;
n = m + 1;
kn[m] = kn[n] = 0L;
for (j = 0; j < 28; j++) {
l = j + (u32) totrot[i];
if (l < 28)
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l - 28];
}
for (/* j = 28 */; j < 56; j++) {
l = j + (u32) totrot[i];
if (l < 56)
pcr[j] = pc1m[l];
else
pcr[j] = pc1m[l - 28];
}
for (j = 0; j < 24; j++) {
if ((int) pcr[(int) pc2[j]] != 0)
kn[m] |= bigbyte[j];
if ((int) pcr[(int) pc2[j + 24]] != 0)
kn[n] |= bigbyte[j];
}
}
cookey(kn, keyout);
}
static void desfunc(u32 *block, const u32 *keys)
{
u32 work, right, leftt;
int cur_round;
leftt = block[0];
right = block[1];
work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
right ^= work;
leftt ^= (work << 4);
work = ((leftt >> 16) ^ right) & 0x0000ffffL;
right ^= work;
leftt ^= (work << 16);
work = ((right >> 2) ^ leftt) & 0x33333333L;
leftt ^= work;
right ^= (work << 2);
work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
leftt ^= work;
right ^= (work << 8);
right = ROLc(right, 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = ROLc(leftt, 1);
for (cur_round = 0; cur_round < 8; cur_round++) {
work = RORc(right, 4) ^ *keys++;
leftt ^= SP7[work & 0x3fL]
^ SP5[(work >> 8) & 0x3fL]
^ SP3[(work >> 16) & 0x3fL]
^ SP1[(work >> 24) & 0x3fL];
work = right ^ *keys++;
leftt ^= SP8[ work & 0x3fL]
^ SP6[(work >> 8) & 0x3fL]
^ SP4[(work >> 16) & 0x3fL]
^ SP2[(work >> 24) & 0x3fL];
work = RORc(leftt, 4) ^ *keys++;
right ^= SP7[ work & 0x3fL]
^ SP5[(work >> 8) & 0x3fL]
^ SP3[(work >> 16) & 0x3fL]
^ SP1[(work >> 24) & 0x3fL];
work = leftt ^ *keys++;
right ^= SP8[ work & 0x3fL]
^ SP6[(work >> 8) & 0x3fL]
^ SP4[(work >> 16) & 0x3fL]
^ SP2[(work >> 24) & 0x3fL];
}
right = RORc(right, 1);
work = (leftt ^ right) & 0xaaaaaaaaL;
leftt ^= work;
right ^= work;
leftt = RORc(leftt, 1);
work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
right ^= work;
leftt ^= (work << 8);
/* -- */
work = ((leftt >> 2) ^ right) & 0x33333333L;
right ^= work;
leftt ^= (work << 2);
work = ((right >> 16) ^ leftt) & 0x0000ffffL;
leftt ^= work;
right ^= (work << 16);
work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
leftt ^= work;
right ^= (work << 4);
block[0] = right;
block[1] = leftt;
}
/* wpa_supplicant/hostapd specific wrapper */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
int i;
u32 ek[32], work[2];
/* Add parity bits to the key */
next = 0;
for (i = 0; i < 7; i++) {
tmp = key[i];
pkey[i] = (tmp >> i) | next | 1;
next = tmp << (7 - i);
}
pkey[i] = next | 1;
deskey(pkey, 0, ek);
work[0] = WPA_GET_BE32(clear);
work[1] = WPA_GET_BE32(clear + 4);
desfunc(work, ek);
WPA_PUT_BE32(cypher, work[0]);
WPA_PUT_BE32(cypher + 4, work[1]);
os_memset(pkey, 0, sizeof(pkey));
os_memset(ek, 0, sizeof(ek));
}
void des_key_setup(const u8 *key, u32 *ek, u32 *dk)
{
deskey(key, 0, ek);
deskey(key, 1, dk);
}
void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt)
{
u32 work[2];
work[0] = WPA_GET_BE32(plain);
work[1] = WPA_GET_BE32(plain + 4);
desfunc(work, ek);
WPA_PUT_BE32(crypt, work[0]);
WPA_PUT_BE32(crypt + 4, work[1]);
}
void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain)
{
u32 work[2];
work[0] = WPA_GET_BE32(crypt);
work[1] = WPA_GET_BE32(crypt + 4);
desfunc(work, dk);
WPA_PUT_BE32(plain, work[0]);
WPA_PUT_BE32(plain + 4, work[1]);
}
void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
{
deskey(key, 0, dkey->ek[0]);
deskey(key + 8, 1, dkey->ek[1]);
deskey(key + 16, 0, dkey->ek[2]);
deskey(key, 1, dkey->dk[2]);
deskey(key + 8, 0, dkey->dk[1]);
deskey(key + 16, 1, dkey->dk[0]);
}
void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
{
u32 work[2];
work[0] = WPA_GET_BE32(plain);
work[1] = WPA_GET_BE32(plain + 4);
desfunc(work, key->ek[0]);
desfunc(work, key->ek[1]);
desfunc(work, key->ek[2]);
WPA_PUT_BE32(crypt, work[0]);
WPA_PUT_BE32(crypt + 4, work[1]);
}
void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
{
u32 work[2];
work[0] = WPA_GET_BE32(crypt);
work[1] = WPA_GET_BE32(crypt + 4);
desfunc(work, key->dk[0]);
desfunc(work, key->dk[1]);
desfunc(work, key->dk[2]);
WPA_PUT_BE32(plain, work[0]);
WPA_PUT_BE32(plain + 4, work[1]);
}

View file

@ -0,0 +1,31 @@
/*
* DES and 3DES-EDE ciphers
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DES_I_H
#define DES_I_H
struct des3_key_s {
u32 ek[3][32];
u32 dk[3][32];
};
void des_key_setup(const u8 *key, u32 *ek, u32 *dk);
void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt);
void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain);
void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
#endif /* DES_I_H */

View file

@ -0,0 +1,40 @@
/*
* Diffie-Hellman group 5 operations
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#include "includes.h"
#include "common.h"
#include "dh_groups.h"
#include "dh_group5.h"
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
{
*publ = dh_init(dh_groups_get(5), priv);
if (*publ == 0)
return NULL;
return (void *) 1;
}
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private)
{
return dh_derive_shared(peer_public, own_private, dh_groups_get(5));
}
void dh5_free(void *ctx)
{
}

View file

@ -0,0 +1,23 @@
/*
* Diffie-Hellman group 5 operations
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
*
* 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.
*
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
* See README and COPYING for more details.
*/
#ifndef DH_GROUP5_H
#define DH_GROUP5_H
void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
const struct wpabuf *own_private);
void dh5_free(void *ctx);
#endif /* DH_GROUP5_H */

Some files were not shown because too many files have changed in this diff Show more