Update hostapd/wpa_supplicant to version 2.5.

Tested by several people on current@/wireless@.

Relnotes:	yes
This commit is contained in:
Rui Paulo 2015-10-18 21:38:25 +00:00
commit 325151a32e
277 changed files with 19676 additions and 6211 deletions

View File

@ -1,5 +1,41 @@
ChangeLog for hostapd
2015-09-27 - v2.5
* fixed WPS UPnP vulnerability with HTTP chunked transfer encoding
[http://w1.fi/security/2015-2/] (CVE-2015-4141)
* fixed WMM Action frame parser
[http://w1.fi/security/2015-3/] (CVE-2015-4142)
* fixed EAP-pwd server missing payload length validation
[http://w1.fi/security/2015-4/]
(CVE-2015-4143, CVE-2015-4144, CVE-2015-4145)
* fixed validation of WPS and P2P NFC NDEF record payload length
[http://w1.fi/security/2015-5/]
* nl80211:
- fixed vendor command handling to check OUI properly
* fixed hlr_auc_gw build with OpenSSL
* hlr_auc_gw: allow Milenage RES length to be reduced
* disable HT for a station that does not support WMM/QoS
* added support for hashed password (NtHash) in EAP-pwd server
* fixed and extended dynamic VLAN cases
* added EAP-EKE server support for deriving Session-Id
* set Acct-Session-Id to a random value to make it more likely to be
unique even if the device does not have a proper clock
* added more 2.4 GHz channels for 20/40 MHz HT co-ex scan
* modified SAE routines to be more robust and PWE generation to be
stronger against timing attacks
* added support for Brainpool Elliptic Curves with SAE
* increases maximum value accepted for cwmin/cwmax
* added support for CCMP-256 and GCMP-256 as group ciphers with FT
* added Fast Session Transfer (FST) module
* removed optional fields from RSNE when using FT with PMF
(workaround for interoperability issues with iOS 8.4)
* added EAP server support for TLS session resumption
* fixed key derivation for Suite B 192-bit AKM (this breaks
compatibility with the earlier version)
* added mechanism to track unconnected stations and do minimal band
steering
* number of small fixes
2015-03-15 - v2.4
* allow OpenSSL cipher configuration to be set for internal EAP server
(openssl_ciphers parameter)

View File

@ -222,9 +222,15 @@ static int hostapd_config_read_eap_user(const char *fname,
return 0;
if (os_strncmp(fname, "sqlite:", 7) == 0) {
#ifdef CONFIG_SQLITE
os_free(conf->eap_user_sqlite);
conf->eap_user_sqlite = os_strdup(fname + 7);
return 0;
#else /* CONFIG_SQLITE */
wpa_printf(MSG_ERROR,
"EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
return -1;
#endif /* CONFIG_SQLITE */
}
f = fopen(fname, "r");
@ -775,6 +781,24 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
}
static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
{
char *pos;
/* for backwards compatibility, translate ' ' in conf str to ',' */
pos = val;
while (pos) {
pos = os_strchr(pos, ' ');
if (pos)
*pos++ = ',';
}
if (freq_range_list_parse(&conf->acs_ch_list, val))
return -1;
return 0;
}
static int hostapd_parse_intlist(int **int_list, char *val)
{
int *list;
@ -875,7 +899,9 @@ static int hostapd_config_read_int10(const char *value)
static int valid_cw(int cw)
{
return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
cw == 32767);
}
@ -886,11 +912,11 @@ enum {
IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
};
static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
char *val)
static int hostapd_config_tx_queue(struct hostapd_config *conf,
const char *name, const char *val)
{
int num;
char *pos;
const char *pos;
struct hostapd_tx_queue_params *queue;
/* skip 'tx_queue_' prefix */
@ -1134,13 +1160,23 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
if (os_strstr(capab, "[BF-ANTENNA-2]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
if (os_strstr(capab, "[BF-ANTENNA-3]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
conf->vht_capab |= (2 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
if (os_strstr(capab, "[BF-ANTENNA-4]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
conf->vht_capab |= (3 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
if (os_strstr(capab, "[SOUNDING-DIMENSION-3]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
conf->vht_capab |= (2 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
if (os_strstr(capab, "[SOUNDING-DIMENSION-4]") &&
(conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
conf->vht_capab |= (3 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
if (os_strstr(capab, "[MU-BEAMFORMER]"))
conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
if (os_strstr(capab, "[MU-BEAMFORMEE]"))
conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
if (os_strstr(capab, "[VHT-TXOP-PS]"))
conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
if (os_strstr(capab, "[HTC-VHT]"))
@ -1699,7 +1735,7 @@ static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
char *str;
str = wpa_config_parse_string(pos, &slen);
if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
os_free(str);
return -1;
@ -1900,7 +1936,7 @@ fail:
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
char *buf, char *pos, int line)
const char *buf, char *pos, int line)
{
if (os_strcmp(buf, "interface") == 0) {
os_strlcpy(conf->bss[0]->iface, pos,
@ -1946,7 +1982,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
} else if (os_strcmp(buf, "ssid") == 0) {
bss->ssid.ssid_len = os_strlen(pos);
if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
if (bss->ssid.ssid_len > SSID_MAX_LEN ||
bss->ssid.ssid_len < 1) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
@ -1957,7 +1993,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "ssid2") == 0) {
size_t slen;
char *str = wpa_config_parse_string(pos, &slen);
if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
os_free(str);
@ -2043,6 +2079,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->private_key_passwd = os_strdup(pos);
} else if (os_strcmp(buf, "check_crl") == 0) {
bss->check_crl = atoi(pos);
} else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
bss->tls_session_lifetime = atoi(pos);
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
@ -2515,13 +2553,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
else if (os_strcmp(pos, "ad") == 0)
conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
else if (os_strcmp(pos, "any") == 0)
conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
else {
wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
line, pos);
return 1;
}
} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
if (os_strcmp(pos, "a") == 0)
if (os_strcmp(pos, "ad") == 0)
bss->wps_rf_bands = WPS_RF_60GHZ;
else if (os_strcmp(pos, "a") == 0)
bss->wps_rf_bands = WPS_RF_50GHZ;
else if (os_strcmp(pos, "g") == 0 ||
os_strcmp(pos, "b") == 0)
@ -2542,12 +2584,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
line);
return 1;
#else /* CONFIG_ACS */
conf->acs = 1;
conf->channel = 0;
#endif /* CONFIG_ACS */
} else
} else {
conf->channel = atoi(pos);
conf->acs = conf->channel == 0;
}
} else if (os_strcmp(buf, "chanlist") == 0) {
if (hostapd_parse_intlist(&conf->chanlist, pos)) {
if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
line);
return 1;
@ -2810,7 +2855,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->wps_pin_requests);
bss->wps_pin_requests = os_strdup(pos);
} else if (os_strcmp(buf, "device_name") == 0) {
if (os_strlen(pos) > 32) {
if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Too long "
"device_name", line);
return 1;
@ -3111,6 +3156,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->disable_dgaf = atoi(pos);
} else if (os_strcmp(buf, "proxy_arp") == 0) {
bss->proxy_arp = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
bss->na_mcast_to_ucast = atoi(pos);
} else if (os_strcmp(buf, "osen") == 0) {
bss->osen = atoi(pos);
} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
@ -3223,6 +3270,24 @@ static int hostapd_config_fill(struct hostapd_config *conf,
bss->bss_load_test_set = 1;
} else if (os_strcmp(buf, "radio_measurements") == 0) {
bss->radio_measurements = atoi(pos);
} else if (os_strcmp(buf, "own_ie_override") == 0) {
struct wpabuf *tmp;
size_t len = os_strlen(pos) / 2;
tmp = wpabuf_alloc(len);
if (!tmp)
return 1;
if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
wpabuf_free(tmp);
wpa_printf(MSG_ERROR,
"Line %d: Invalid own_ie_override '%s'",
line, pos);
return 1;
}
wpabuf_free(bss->own_ie_override);
bss->own_ie_override = tmp;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strcmp(buf, "vendor_elements") == 0) {
struct wpabuf *elems;
@ -3276,6 +3341,74 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "wowlan_triggers") == 0) {
os_free(bss->wowlan_triggers);
bss->wowlan_triggers = os_strdup(pos);
#ifdef CONFIG_FST
} else if (os_strcmp(buf, "fst_group_id") == 0) {
size_t len = os_strlen(pos);
if (!len || len >= sizeof(conf->fst_cfg.group_id)) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid fst_group_id value '%s'",
line, pos);
return 1;
}
if (conf->fst_cfg.group_id[0]) {
wpa_printf(MSG_ERROR,
"Line %d: Duplicate fst_group value '%s'",
line, pos);
return 1;
}
os_strlcpy(conf->fst_cfg.group_id, pos,
sizeof(conf->fst_cfg.group_id));
} else if (os_strcmp(buf, "fst_priority") == 0) {
char *endp;
long int val;
if (!*pos) {
wpa_printf(MSG_ERROR,
"Line %d: fst_priority value not supplied (expected 1..%u)",
line, FST_MAX_PRIO_VALUE);
return -1;
}
val = strtol(pos, &endp, 0);
if (*endp || val < 1 || val > FST_MAX_PRIO_VALUE) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid fst_priority %ld (%s) (expected 1..%u)",
line, val, pos, FST_MAX_PRIO_VALUE);
return 1;
}
conf->fst_cfg.priority = (u8) val;
} else if (os_strcmp(buf, "fst_llt") == 0) {
char *endp;
long int val;
if (!*pos) {
wpa_printf(MSG_ERROR,
"Line %d: fst_llt value not supplied (expected 1..%u)",
line, FST_MAX_LLT_MS);
return -1;
}
val = strtol(pos, &endp, 0);
if (*endp || val < 1 || val > FST_MAX_LLT_MS) {
wpa_printf(MSG_ERROR,
"Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
line, val, pos, FST_MAX_LLT_MS);
return 1;
}
conf->fst_cfg.llt = (u32) val;
#endif /* CONFIG_FST */
} else if (os_strcmp(buf, "track_sta_max_num") == 0) {
conf->track_sta_max_num = atoi(pos);
} else if (os_strcmp(buf, "track_sta_max_age") == 0) {
conf->track_sta_max_age = atoi(pos);
} else if (os_strcmp(buf, "no_probe_resp_if_seen_on") == 0) {
os_free(bss->no_probe_resp_if_seen_on);
bss->no_probe_resp_if_seen_on = os_strdup(pos);
} else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
os_free(bss->no_auth_if_seen_on);
bss->no_auth_if_seen_on = os_strdup(pos);
} else {
wpa_printf(MSG_ERROR,
"Line %d: unknown configuration item '%s'",
@ -3378,7 +3511,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, char *field, char *value)
struct hostapd_bss_config *bss, const char *field,
char *value)
{
int errors;
size_t i;

View File

@ -11,7 +11,7 @@
struct hostapd_config * hostapd_config_read(const char *fname);
int hostapd_set_iface(struct hostapd_config *conf,
struct hostapd_bss_config *bss, char *field,
struct hostapd_bss_config *bss, const char *field,
char *value);
#endif /* CONFIG_FILE_H */

File diff suppressed because it is too large Load Diff

View File

@ -240,6 +240,12 @@ CONFIG_IPV6=y
# requirements described above.
#CONFIG_NO_RANDOM_POOL=y
# Should we use poll instead of select? Select is used by default.
#CONFIG_ELOOP_POLL=y
# Should we use epoll instead of select? Select is used by default.
#CONFIG_ELOOP_EPOLL=y
# Select TLS implementation
# openssl = OpenSSL (default)
# gnutls = GnuTLS
@ -283,6 +289,12 @@ CONFIG_IPV6=y
# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
#CONFIG_SQLITE=y
# Enable Fast Session Transfer (FST)
#CONFIG_FST=y
# Enable CLI commands for FST testing
#CONFIG_FST_TEST=y
# Testing options
# This can be used to enable some testing options (see also the example
# configuration file) that are really useful only for testing clients that

View File

@ -87,6 +87,7 @@ struct milenage_parameters {
u8 amf[2];
u8 sqn[6];
int set;
size_t res_len;
};
static struct milenage_parameters *milenage_db = NULL;
@ -96,6 +97,7 @@ static struct milenage_parameters *milenage_db = NULL;
#define EAP_AKA_RAND_LEN 16
#define EAP_AKA_AUTN_LEN 16
#define EAP_AKA_AUTS_LEN 14
#define EAP_AKA_RES_MIN_LEN 4
#define EAP_AKA_RES_MAX_LEN 16
#define EAP_AKA_IK_LEN 16
#define EAP_AKA_CK_LEN 16
@ -124,7 +126,8 @@ static int db_table_create_milenage(sqlite3 *db)
" ki CHAR(32) NOT NULL,"
" opc CHAR(32) NOT NULL,"
" amf CHAR(4) NOT NULL,"
" sqn CHAR(12) NOT NULL"
" sqn CHAR(12) NOT NULL,"
" res_len INTEGER"
");";
printf("Adding database table for milenage information\n");
@ -190,6 +193,10 @@ static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
printf("Invalid sqn value in database\n");
return -1;
}
if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
m->res_len = atoi(argv[i]);
}
}
return 0;
@ -206,8 +213,7 @@ static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
"%llu", imsi);
os_snprintf(cmd, sizeof(cmd),
"SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
imsi);
"SELECT * FROM milenage WHERE imsi=%llu;", imsi);
if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
NULL) != SQLITE_OK)
return NULL;
@ -424,7 +430,7 @@ static int read_milenage(const char *fname)
while (fgets(buf, sizeof(buf), f)) {
line++;
/* Parse IMSI Ki OPc AMF SQN */
/* Parse IMSI Ki OPc AMF SQN [RES_len] */
buf[sizeof(buf) - 1] = '\0';
if (buf[0] == '#')
continue;
@ -515,7 +521,19 @@ static int read_milenage(const char *fname)
ret = -1;
break;
}
pos = pos2 + 1;
if (pos2) {
pos = pos2 + 1;
m->res_len = atoi(pos);
if (m->res_len &&
(m->res_len < EAP_AKA_RES_MIN_LEN ||
m->res_len > EAP_AKA_RES_MAX_LEN)) {
printf("%s:%d - Invalid RES_len (%s)\n",
fname, line, pos);
ret = -1;
break;
}
}
m->next = milenage_db;
milenage_db = m;
@ -532,7 +550,7 @@ static int read_milenage(const char *fname)
static void update_milenage_file(const char *fname)
{
FILE *f, *f2;
char buf[500], *pos;
char name[500], buf[500], *pos;
char *end = buf + sizeof(buf);
struct milenage_parameters *m;
size_t imsi_len;
@ -543,10 +561,10 @@ static void update_milenage_file(const char *fname)
return;
}
snprintf(buf, sizeof(buf), "%s.new", fname);
f2 = fopen(buf, "w");
snprintf(name, sizeof(name), "%s.new", fname);
f2 = fopen(name, "w");
if (f2 == NULL) {
printf("Could not write Milenage data file '%s'\n", buf);
printf("Could not write Milenage data file '%s'\n", name);
fclose(f);
return;
}
@ -588,14 +606,14 @@ static void update_milenage_file(const char *fname)
fclose(f2);
fclose(f);
snprintf(buf, sizeof(buf), "%s.bak", fname);
if (rename(fname, buf) < 0) {
snprintf(name, sizeof(name), "%s.bak", fname);
if (rename(fname, name) < 0) {
perror("rename");
return;
}
snprintf(buf, sizeof(buf), "%s.new", fname);
if (rename(buf, fname) < 0) {
snprintf(name, sizeof(name), "%s.new", fname);
if (rename(name, fname) < 0) {
perror("rename");
return;
}
@ -798,6 +816,10 @@ static int aka_req_auth(char *imsi, char *resp, size_t resp_len)
}
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
autn, ik, ck, res, &res_len);
if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
m->res_len <= EAP_AKA_RES_MAX_LEN &&
m->res_len < res_len)
res_len = m->res_len;
} else {
printf("Unknown IMSI: %s\n", imsi);
#ifdef AKA_USE_FIXED_TEST_VALUES

View File

@ -5,8 +5,10 @@
# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
# dummy values will need to be included in this file.
# IMSI Ki OPc AMF SQN
# IMSI Ki OPc AMF SQN [RES_len]
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
# Example using truncated 32-bit RES instead of 64-bit default
232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
# These values are from Test Set 19 which has the AMF separation bit set to 1
# and as such, is suitable for EAP-AKA' test.

View File

@ -127,7 +127,9 @@ ssid=test
# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
# specify band)
# specify band). When using ACS (see channel parameter), a special value "any"
# can be used to indicate that any support band can be used. This special case
# is currently supported only with drivers with which offloaded ACS is used.
# Default: IEEE 802.11b
hw_mode=g
@ -170,8 +172,11 @@ channel=1
# Channel list restriction. This option allows hostapd to select one of the
# provided channels when a channel should be automatically selected.
# Default: not set (allow any enabled channel to be selected)
# Channel list can be provided as range using hyphen ('-') or individual
# channels can be specified by space (' ') seperated values
# Default: all channels allowed in selected hw_mode
#chanlist=100 104 108 112 116
#chanlist=1 6 11-13
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@ -275,8 +280,9 @@ ignore_broadcast_ssid=0
# (data0 is the highest priority queue)
# parameters:
# aifs: AIFS (default 2)
# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
# cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
# cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191,
# 16383, 32767)
# cwmax: cwMax (same values as cwMin, cwMax >= cwMin)
# burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
# bursting
#
@ -337,8 +343,9 @@ ignore_broadcast_ssid=0
# note - txop_limit is in units of 32microseconds
# note - acm is admission control mandatory flag. 0 = admission control not
# required, 1 = mandatory
# note - here cwMin and cmMax are in exponent form. the actual cw value used
# will be (2^n)-1 where n is the value given here
# note - Here cwMin and cmMax are in exponent form. The actual cw value used
# will be (2^n)-1 where n is the value given here. The allowed range for these
# wmm_ac_??_{cwmin,cwmax} is 0..15 with cwmax >= cwmin.
#
wmm_enabled=1
#
@ -575,14 +582,16 @@ wmm_ac_vo_acm=0
# 0 = Not supported (default)
# 1 = Supported
#
# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
# Compressed Steering Number of Beamformer Antennas Supported:
# [BF-ANTENNA-2] [BF-ANTENNA-3] [BF-ANTENNA-4]
# Beamformee's capability indicating the maximum number of beamformer
# antennas the beamformee can support when sending compressed beamforming
# feedback
# If SU beamformer capable, set to maximum value minus 1
# else reserved (default)
#
# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
# Number of Sounding Dimensions:
# [SOUNDING-DIMENSION-2] [SOUNDING-DIMENSION-3] [SOUNDING-DIMENSION-4]
# Beamformer's capability indicating the maximum value of the NUM_STS parameter
# in the TXVECTOR of a VHT NDP
# If SU beamformer capable, set to maximum value minus 1
@ -593,11 +602,6 @@ wmm_ac_vo_acm=0
# 0 = Not supported or sent by Non-AP STA (default)
# 1 = Supported
#
# MU Beamformee Capable: [MU-BEAMFORMEE]
# Indicates support for operation as an MU beamformee
# 0 = Not supported or sent by AP (default)
# 1 = Supported
#
# VHT TXOP PS: [VHT-TXOP-PS]
# Indicates whether or not the AP supports VHT TXOP Power Save Mode
# or whether or not the STA is in VHT TXOP Power Save mode
@ -764,6 +768,12 @@ eap_server=0
# 2 = check all CRLs in the certificate path
#check_crl=1
# TLS Session Lifetime in seconds
# This can be used to allow TLS sessions to be cached and resumed with an
# abbreviated handshake when using EAP-TLS/TTLS/PEAP.
# (default: 0 = session caching and resumption disabled)
#tls_session_lifetime=3600
# Cached OCSP stapling response (DER encoded)
# If set, this file is sent as a certificate status response by the EAP server
# if the EAP peer requests certificate status in the ClientHello message.
@ -787,7 +797,7 @@ eap_server=0
# is in DSA parameters format, it will be automatically converted into DH
# params. This parameter is required if anonymous EAP-FAST is used.
# You can generate DH parameters file with OpenSSL, e.g.,
# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
# "openssl dhparam -out /etc/hostapd.dh.pem 2048"
#dh_file=/etc/hostapd.dh.pem
# OpenSSL cipher string
@ -1247,6 +1257,11 @@ own_ip_addr=127.0.0.1
# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
#pmk_r1_push=1
# Whether to enable FT-over-DS
# 0 = FT-over-DS disabled
# 1 = FT-over-DS enabled (default)
#ft_over_ds=1
##### Neighbor table ##########################################################
# Maximum number of entries kept in AP table (either for neigbor table or for
# detecting Overlapping Legacy BSS Condition). The oldest entry will be
@ -1264,6 +1279,43 @@ own_ip_addr=127.0.0.1
# default: 60
#ap_table_expiration_time=3600
# Maximum number of stations to track on the operating channel
# This can be used to detect dualband capable stations before they have
# associated, e.g., to provide guidance on which colocated BSS to use.
# Default: 0 (disabled)
#track_sta_max_num=100
# Maximum age of a station tracking entry in seconds
# Default: 180
#track_sta_max_age=180
# Do not reply to group-addressed Probe Request from a station that was seen on
# another radio.
# Default: Disabled
#
# This can be used with enabled track_sta_max_num configuration on another
# interface controlled by the same hostapd process to restrict Probe Request
# frame handling from replying to group-addressed Probe Request frames from a
# station that has been detected to be capable of operating on another band,
# e.g., to try to reduce likelihood of the station selecting a 2.4 GHz BSS when
# the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
#
# Note: Enabling this can cause connectivity issues and increase latency for
# discovering the AP.
#no_probe_resp_if_seen_on=wlan1
# Reject authentication from a station that was seen on another radio.
# Default: Disabled
#
# This can be used with enabled track_sta_max_num configuration on another
# interface controlled by the same hostapd process to reject authentication
# attempts from a station that has been detected to be capable of operating on
# another band, e.g., to try to reduce likelihood of the station selecting a
# 2.4 GHz BSS when the AP operates both a 2.4 GHz and 5 GHz BSS concurrently.
#
# Note: Enabling this can cause connectivity issues and increase latency for
# connecting with the AP.
#no_auth_if_seen_on=wlan1
##### Wi-Fi Protected Setup (WPS) #############################################
@ -1430,7 +1482,7 @@ own_ip_addr=127.0.0.1
# 12-digit, all-numeric code that identifies the consumer package.
#upc=123456789012
# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band, ad = 60 GHz)
# This value should be set according to RF band(s) supported by the AP if
# hw_mode is not set. For dual band dual concurrent devices, this needs to be
# set to ag to allow both RF bands to be advertized.
@ -1490,6 +1542,13 @@ own_ip_addr=127.0.0.1
# 1 = enabled
#proxy_arp=1
# IPv6 Neighbor Advertisement multicast-to-unicast conversion
# This can be used with Proxy ARP to allow multicast NAs to be forwarded to
# associated STAs using link layer unicast delivery.
# 0 = disabled (default)
# 1 = enabled
#na_mcast_to_ucast=0
##### IEEE 802.11u-2011 #######################################################
# Enable Interworking service
@ -1738,6 +1797,32 @@ own_ip_addr=127.0.0.1
#
#osu_server_uri=...
##### Fast Session Transfer (FST) support #####################################
#
# The options in this section are only available when the build configuration
# option CONFIG_FST is set while compiling hostapd. They allow this interface
# to be a part of FST setup.
#
# FST is the transfer of a session from a channel to another channel, in the
# same or different frequency bands.
#
# For detals, see IEEE Std 802.11ad-2012.
# Identifier of an FST Group the interface belongs to.
#fst_group_id=bond0
# Interface priority within the FST Group.
# Announcing a higher priority for an interface means declaring it more
# preferable for FST switch.
# fst_priority is in 1..255 range with 1 being the lowest priority.
#fst_priority=100
# Default LLT value for this interface in milliseconds. The value used in case
# no value provided during session setup. Default is 50 ms.
# fst_llt is in 1..4294967 range (due to spec limitation, see 10.32.2.2
# Transitioning between states).
#fst_llt=100
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration

View File

@ -10,22 +10,23 @@
#include <dirent.h>
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/edit.h"
#include "common/version.h"
static const char *hostapd_cli_version =
static const char *const hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
static const char *const hostapd_cli_license =
"This software may be distributed under the terms of the BSD license.\n"
"See README for more details.\n";
static const char *hostapd_cli_full_license =
static const char *const hostapd_cli_full_license =
"This software may be distributed under the terms of the BSD license.\n"
"\n"
"Redistribution and use in source and binary forms, with or without\n"
@ -56,7 +57,7 @@ static const char *hostapd_cli_full_license =
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
static const char *commands_help =
static const char *const commands_help =
"Commands:\n"
" mib get MIB variables (dot1x, dot11, radius)\n"
" sta <addr> get MIB variables for one station\n"
@ -96,6 +97,7 @@ static int hostapd_cli_attached = 0;
#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
#endif /* CONFIG_CTRL_IFACE_DIR */
static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
static const char *client_socket_dir = NULL;
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
@ -111,13 +113,15 @@ static void usage(void)
"\n"
"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
"[-a<path>] \\\n"
" [-G<ping interval>] [command..]\n"
" [-P<pid file>] [-G<ping interval>] [command..]\n"
"\n"
"Options:\n"
" -h help (show this usage text)\n"
" -v shown version information\n"
" -p<path> path to find control sockets (default: "
"/var/run/hostapd)\n"
" -s<dir_path> dir path to open client sockets (default: "
CONFIG_CTRL_IFACE_DIR ")\n"
" -a<file> run in daemon mode executing the action file "
"based on events\n"
" from hostapd\n"
@ -144,7 +148,14 @@ static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
return NULL;
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
ctrl_conn = wpa_ctrl_open(cfile);
if (client_socket_dir && client_socket_dir[0] &&
access(client_socket_dir, F_OK) < 0) {
perror(client_socket_dir);
free(cfile);
return NULL;
}
ctrl_conn = wpa_ctrl_open2(cfile, client_socket_dir);
free(cfile);
return ctrl_conn;
}
@ -541,7 +552,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[256];
char ssid_hex[2 * 32 + 1];
char ssid_hex[2 * SSID_MAX_LEN + 1];
char key_hex[2 * 64 + 1];
int i;
@ -552,7 +563,7 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
}
ssid_hex[0] = '\0';
for (i = 0; i < 32; i++) {
for (i = 0; i < SSID_MAX_LEN; i++) {
if (argv[0][i] == '\0')
break;
os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
@ -921,6 +932,35 @@ static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
#ifdef CONFIG_FST
static int hostapd_cli_cmd_fst(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
int res;
int i;
int total;
if (argc <= 0) {
printf("FST command: parameters are required.\n");
return -1;
}
total = os_snprintf(cmd, sizeof(cmd), "FST-MANAGER");
for (i = 0; i < argc; i++) {
res = os_snprintf(cmd + total, sizeof(cmd) - total, " %s",
argv[i]);
if (os_snprintf_error(sizeof(cmd) - total, res)) {
printf("Too long fst command.\n");
return -1;
}
total += res;
}
return wpa_ctrl_command(ctrl, cmd);
}
#endif /* CONFIG_FST */
static int hostapd_cli_cmd_chan_switch(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
@ -1009,12 +1049,31 @@ static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
}
static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
int res;
res = os_snprintf(cmd, sizeof(cmd), "LOG_LEVEL%s%s%s%s",
argc >= 1 ? " " : "",
argc >= 1 ? argv[0] : "",
argc == 2 ? " " : "",
argc == 2 ? argv[1] : "");
if (os_snprintf_error(sizeof(cmd), res)) {
printf("Too long option\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
}
struct hostapd_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
};
static struct hostapd_cli_cmd hostapd_cli_commands[] = {
static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "ping", hostapd_cli_cmd_ping },
{ "mib", hostapd_cli_cmd_mib },
{ "relog", hostapd_cli_cmd_relog },
@ -1048,6 +1107,9 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "get_config", hostapd_cli_cmd_get_config },
{ "help", hostapd_cli_cmd_help },
{ "interface", hostapd_cli_cmd_interface },
#ifdef CONFIG_FST
{ "fst", hostapd_cli_cmd_fst },
#endif /* CONFIG_FST */
{ "level", hostapd_cli_cmd_level },
{ "license", hostapd_cli_cmd_license },
{ "quit", hostapd_cli_cmd_quit },
@ -1063,13 +1125,14 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
{ "reload", hostapd_cli_cmd_reload },
{ "disable", hostapd_cli_cmd_disable },
{ "erp_flush", hostapd_cli_cmd_erp_flush },
{ "log_level", hostapd_cli_cmd_log_level },
{ NULL, NULL }
};
static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
struct hostapd_cli_cmd *cmd, *match = NULL;
const struct hostapd_cli_cmd *cmd, *match = NULL;
int count;
count = 0;
@ -1284,7 +1347,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
c = getopt(argc, argv, "a:BhG:i:p:v");
c = getopt(argc, argv, "a:BhG:i:p:P:s:v");
if (c < 0)
break;
switch (c) {
@ -1310,6 +1373,12 @@ int main(int argc, char *argv[])
case 'p':
ctrl_iface_dir = optarg;
break;
case 'P':
pid_file = optarg;
break;
case 's':
client_socket_dir = optarg;
break;
default:
usage();
return -1;

View File

@ -24,6 +24,7 @@
#include "ap/hostapd.h"
#include "ap/ap_config.h"
#include "ap/ap_drv_ops.h"
#include "fst/fst.h"
#include "config_file.h"
#include "eap_register.h"
#include "ctrl_iface.h"
@ -533,6 +534,28 @@ static int gen_uuid(const char *txt_addr)
#endif /* CONFIG_WPS */
#ifndef HOSTAPD_CLEANUP_INTERVAL
#define HOSTAPD_CLEANUP_INTERVAL 10
#endif /* HOSTAPD_CLEANUP_INTERVAL */
static int hostapd_periodic_call(struct hostapd_iface *iface, void *ctx)
{
hostapd_periodic_iface(iface);
return 0;
}
/* Periodic cleanup tasks */
static void hostapd_periodic(void *eloop_ctx, void *timeout_ctx)
{
struct hapd_interfaces *interfaces = eloop_ctx;
eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
hostapd_periodic, interfaces, NULL);
hostapd_for_each_interface(interfaces, hostapd_periodic_call, NULL);
}
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
@ -561,6 +584,7 @@ int main(int argc, char *argv[])
interfaces.global_iface_path = NULL;
interfaces.global_iface_name = NULL;
interfaces.global_ctrl_sock = -1;
interfaces.global_ctrl_dst = NULL;
for (;;) {
c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
@ -661,10 +685,24 @@ int main(int argc, char *argv[])
}
if (hostapd_global_init(&interfaces, entropy_file)) {
wpa_printf(MSG_ERROR, "Failed to initilize global context");
wpa_printf(MSG_ERROR, "Failed to initialize global context");
return -1;
}
eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
hostapd_periodic, &interfaces, NULL);
if (fst_global_init()) {
wpa_printf(MSG_ERROR,
"Failed to initialize global FST context");
goto out;
}
#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
if (!fst_global_add_ctrl(fst_ctrl_cli))
wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */
/* Allocate and parse configuration for full interface files */
for (i = 0; i < interfaces.count; i++) {
interfaces.iface[i] = hostapd_interface_init(&interfaces,
@ -749,6 +787,7 @@ int main(int argc, char *argv[])
}
os_free(interfaces.iface);
eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
hostapd_global_deinit(pid_file);
os_free(pid_file);
@ -758,6 +797,8 @@ int main(int argc, char *argv[])
os_free(bss_config);
fst_global_deinit();
os_program_deinit();
return ret;

View File

@ -67,7 +67,13 @@ OBJS += ../../src/crypto/sha256-internal.o
CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs)
# Allow static/custom linking of libcurl.
ifdef CUST_CURL_LINKAGE
LIBS += ${CUST_CURL_LINKAGE}
else
LIBS += -lcurl
endif
CFLAGS += -DEAP_TLS_OPENSSL
LIBS += -lssl -lcrypto

View File

@ -25,6 +25,8 @@
#include "crypto/sha256.h"
#include "osu_client.h"
const char *spp_xsd_fname = "spp.xsd";
void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
{
@ -540,6 +542,7 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
uri);
write_result(ctx, "Unsupported location for addMO to "
"add PPS MO (extra directory): '%s'", uri);
free(fqdn);
return -1;
}
*pos = '\0'; /* remove trailing slash and PPS node name */
@ -547,8 +550,9 @@ int hs20_add_pps_mo(struct hs20_osu_client *ctx, const char *uri,
wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
if (!server_dnsname_suffix_match(ctx, fqdn)) {
wpa_printf(MSG_INFO, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
fqdn);
wpa_printf(MSG_INFO,
"FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
fqdn, (int) ctx->server_dnsname_count);
write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
fqdn);
free(fqdn);
@ -2094,10 +2098,14 @@ static int osu_connect(struct hs20_osu_client *ctx, const char *bssid,
}
ctx->no_reconnect = 1;
if (methods & 0x02)
if (methods & 0x02) {
wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
res = cmd_prov(ctx, url);
else if (methods & 0x01)
} else if (methods & 0x01) {
wpa_printf(MSG_DEBUG,
"Calling cmd_oma_dm_prov from osu_connect");
res = cmd_oma_dm_prov(ctx, url);
}
wpa_printf(MSG_INFO, "Remove OSU network connection");
write_summary(ctx, "Remove OSU network connection");
@ -2139,7 +2147,7 @@ static int cmd_osu_select(struct hs20_osu_client *ctx, const char *dir,
snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
osu = parse_osu_providers(fname, &osu_count);
if (osu == NULL) {
wpa_printf(MSG_INFO, "Could not any OSU providers from %s",
wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
fname);
write_result(ctx, "No OSU providers available");
return -1;
@ -2290,12 +2298,19 @@ selected:
}
if (connect == 2) {
if (last->methods & 0x02)
if (last->methods & 0x02) {
wpa_printf(MSG_DEBUG,
"Calling cmd_prov from cmd_osu_select");
ret = cmd_prov(ctx, last->url);
else if (last->methods & 0x01)
} else if (last->methods & 0x01) {
wpa_printf(MSG_DEBUG,
"Calling cmd_oma_dm_prov from cmd_osu_select");
ret = cmd_oma_dm_prov(ctx, last->url);
else
} else {
wpa_printf(MSG_DEBUG,
"No supported OSU provisioning method");
ret = -1;
}
} else if (connect)
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
last->url, last->methods,
@ -2690,7 +2705,7 @@ static char * get_hostname(const char *url)
end = os_strchr(pos, '/');
end2 = os_strchr(pos, ':');
if (end && end2 && end2 < end)
if ((end && end2 && end2 < end) || (!end && end2))
end = end2;
if (end)
end--;
@ -2720,8 +2735,8 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
int found;
char *host = NULL;
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d)",
!ctx->no_osu_cert_validation);
wpa_printf(MSG_INFO, "osu_cert_cb(osu_cert_validation=%d, url=%s)",
!ctx->no_osu_cert_validation, ctx->server_url);
host = get_hostname(ctx->server_url);
@ -2810,17 +2825,21 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
char *name = ctx->icon_filename[j];
size_t name_len = os_strlen(name);
wpa_printf(MSG_INFO, "Looking for icon file name '%s' match",
name);
wpa_printf(MSG_INFO,
"[%i] Looking for icon file name '%s' match",
j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
size_t uri_len = os_strlen(logo->uri);
char *pos;
wpa_printf(MSG_INFO, "Comparing to '%s' uri_len=%d name_len=%d",
logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len)
wpa_printf(MSG_INFO,
"[%i] Comparing to '%s' uri_len=%d name_len=%d",
i, logo->uri, (int) uri_len, (int) name_len);
if (uri_len < 1 + name_len) {
wpa_printf(MSG_INFO, "URI Length is too short");
continue;
}
pos = &logo->uri[uri_len - name_len - 1];
if (*pos != '/')
continue;
@ -2847,17 +2866,30 @@ static int osu_cert_cb(void *_ctx, struct http_cert *cert)
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
if (logo->hash_len != 32)
if (logo->hash_len != 32) {
wpa_printf(MSG_INFO,
"[%i][%i] Icon hash length invalid (should be 32): %d",
j, i, (int) logo->hash_len);
continue;
}
if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
found = 1;
break;
}
wpa_printf(MSG_DEBUG,
"[%u][%u] Icon hash did not match", j, i);
wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
logo->hash, 32);
wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
ctx->icon_hash[j], 32);
}
if (!found) {
wpa_printf(MSG_INFO, "No icon hash match found");
write_result(ctx, "No icon hash match found");
wpa_printf(MSG_INFO,
"No icon hash match (by hash) found");
write_result(ctx,
"No icon hash match (by hash) found");
return -1;
}
}
@ -2955,6 +2987,7 @@ static void usage(void)
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
" [-x<spp.xsd file name>] \\\n"
" <command> [arguments..]\n"
"commands:\n"
"- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n"
@ -2996,7 +3029,7 @@ int main(int argc, char *argv[])
return -1;
for (;;) {
c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:");
c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
if (c < 0)
break;
switch (c) {
@ -3034,6 +3067,9 @@ int main(int argc, char *argv[])
case 'w':
wpas_ctrl_path = optarg;
break;
case 'x':
spp_xsd_fname = optarg;
break;
case 'h':
default:
usage();
@ -3108,6 +3144,7 @@ int main(int argc, char *argv[])
exit(0);
}
ctx.ca_fname = argv[optind + 2];
wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
cmd_prov(&ctx, argv[optind + 1]);
} else if (strcmp(argv[optind], "sim_prov") == 0) {
if (argc - optind < 2) {

View File

@ -21,6 +21,8 @@
#include "osu_client.h"
extern const char *spp_xsd_fname;
static int hs20_spp_update_response(struct hs20_osu_client *ctx,
const char *session_id,
const char *spp_status,
@ -59,7 +61,7 @@ static int hs20_spp_validate(struct hs20_osu_client *ctx, xml_node_t *node,
return -1;
}
ret = xml_validate(xctx, node, "spp.xsd", &err);
ret = xml_validate(xctx, node, spp_xsd_fname, &err);
if (ret < 0) {
wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
write_summary(ctx, "SPP XML schema validation failed");
@ -77,9 +79,14 @@ static void add_mo_container(struct xml_node_ctx *ctx, xml_namespace_t *ns,
xml_node_t *fnode, *tnds;
char *str;
errno = 0;
fnode = node_from_file(ctx, fname);
if (!fnode)
if (!fnode) {
wpa_printf(MSG_ERROR,
"Failed to create XML node from file: %s, possible error: %s",
fname, strerror(errno));
return;
}
tnds = mo_to_tnds(ctx, fnode, 0, urn, "syncml:dmddf1.2");
xml_node_free(ctx, fnode);
if (!tnds)
@ -952,7 +959,9 @@ int cmd_prov(struct hs20_osu_client *ctx, const char *url)
return -1;
}
wpa_printf(MSG_INFO, "Credential provisioning requested");
wpa_printf(MSG_INFO,
"Credential provisioning requested - URL: %s ca_fname: %s",
url, ctx->ca_fname ? ctx->ca_fname : "N/A");
os_free(ctx->server_url);
ctx->server_url = os_strdup(url);

View File

@ -0,0 +1,398 @@
This patch adds support for TLS SessionTicket extension (RFC 5077) for
the parts used by EAP-FAST (RFC 4851).
This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
OpenSSL 0.9.8zf does not enable TLS extension support by default, so it
will need to be enabled by adding enable-tlsext to config script
command line.
diff -upr openssl-0.9.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
--- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
@@ -760,6 +760,23 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
+#ifndef OPENSSL_NO_TLSEXT
+ /* check if we want to resume the session based on external pre-shared secret */
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
+ SSL_CIPHER *pref_cipher = NULL;
+
+ s->session->master_key_length = sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key,
+ &s->session->master_key_length,
+ NULL, &pref_cipher,
+ s->tls_session_secret_cb_arg)) {
+ s->session->cipher = pref_cipher ?
+ pref_cipher : ssl_get_cipher_by_char(s, p + j);
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ }
+ }
+#endif /* OPENSSL_NO_TLSEXT */
+
if (j != 0 && j == s->session->session_id_length
&& memcmp(p, s->session->session_id, j) == 0) {
if (s->sid_ctx_length != s->session->sid_ctx_length
@@ -2684,12 +2701,8 @@ int ssl3_check_finished(SSL *s)
{
int ok;
long n;
- /*
- * If we have no ticket or session ID is non-zero length (a match of a
- * non-zero session length would never reach here) it cannot be a resumed
- * session.
- */
- if (!s->session->tlsext_tick || s->session->session_id_length)
+ /* If we have no ticket it cannot be a resumed session. */
+ if (!s->session->tlsext_tick)
return 1;
/*
* this function is called when we really expect a Certificate message,
diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
--- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
@@ -999,6 +999,59 @@ int ssl3_get_client_hello(SSL *s)
SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
goto err;
}
+
+ /* Check if we want to use external pre-shared secret for this
+ * handshake for not reused session only. We need to generate
+ * server_random before calling tls_session_secret_cb in order to allow
+ * SessionTicket processing to use it in key derivation. */
+ {
+ unsigned long Time;
+ unsigned char *pos;
+ Time = (unsigned long)time(NULL); /* Time */
+ pos = s->s3->server_random;
+ l2n(Time, pos);
+ if (RAND_pseudo_bytes(pos, SSL3_RANDOM_SIZE - 4) <= 0) {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
+
+ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
+ SSL_CIPHER *pref_cipher = NULL;
+
+ s->session->master_key_length = sizeof(s->session->master_key);
+ if (s->tls_session_secret_cb(s, s->session->master_key,
+ &s->session->master_key_length,
+ ciphers, &pref_cipher,
+ s->tls_session_secret_cb_arg)) {
+ s->hit = 1;
+ s->session->ciphers = ciphers;
+ s->session->verify_result = X509_V_OK;
+
+ ciphers = NULL;
+
+ /* check if some cipher was preferred by call back */
+ pref_cipher = pref_cipher ? pref_cipher :
+ ssl3_choose_cipher(s, s->session->ciphers,
+ SSL_get_ciphers(s));
+ if (pref_cipher == NULL) {
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_NO_SHARED_CIPHER);
+ goto f_err;
+ }
+
+ s->session->cipher = pref_cipher;
+
+ if (s->cipher_list)
+ sk_SSL_CIPHER_free(s->cipher_list);
+
+ if (s->cipher_list_by_id)
+ sk_SSL_CIPHER_free(s->cipher_list_by_id);
+
+ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
+ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
+ }
+ }
#endif
/*
* Worst case, we will use the NULL compression, but if we have other
@@ -1143,15 +1196,21 @@ int ssl3_send_server_hello(SSL *s)
unsigned char *buf;
unsigned char *p, *d;
int i, sl;
- unsigned long l, Time;
+ unsigned long l;
+#ifdef OPENSSL_NO_TLSEXT
+ unsigned long Time;
+#endif
if (s->state == SSL3_ST_SW_SRVR_HELLO_A) {
buf = (unsigned char *)s->init_buf->data;
+#ifdef OPENSSL_NO_TLSEXT
p = s->s3->server_random;
+ /* Generate server_random if it was not needed previously */
Time = (unsigned long)time(NULL); /* Time */
l2n(Time, p);
if (RAND_pseudo_bytes(p, SSL3_RANDOM_SIZE - 4) <= 0)
return -1;
+#endif
/* Do the message type and length last */
d = p = &(buf[4]);
diff -upr openssl-0.9.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
--- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
@@ -316,6 +316,7 @@ static ERR_STRING_DATA SSL_str_functs[]
{ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
{ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
{ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
+ {ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
{0, NULL}
};
diff -upr openssl-0.9.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
--- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
@@ -349,6 +349,7 @@ extern "C" {
* function parameters used to prototype callbacks in SSL_CTX.
*/
typedef struct ssl_st *ssl_crock_st;
+typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
/* used to hold info on the particular ciphers used */
typedef struct ssl_cipher_st {
@@ -366,6 +367,12 @@ typedef struct ssl_cipher_st {
DECLARE_STACK_OF(SSL_CIPHER)
+typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data,
+ int len, void *arg);
+typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg);
+
/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
typedef struct ssl_method_st {
int version;
@@ -1116,6 +1123,18 @@ struct ssl_st {
int tlsext_ocsp_resplen;
/* RFC4507 session ticket expected to be received or sent */
int tlsext_ticket_expected;
+
+ /* TLS Session Ticket extension override */
+ TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
+
+ /* TLS Session Ticket extension callback */
+ tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
+ void *tls_session_ticket_ext_cb_arg;
+
+ /* TLS pre-shared secret session resumption */
+ tls_session_secret_cb_fn tls_session_secret_cb;
+ void *tls_session_secret_cb_arg;
+
SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */
# define session_ctx initial_ctx
# else
@@ -1772,6 +1791,17 @@ void *SSL_COMP_get_compression_methods(v
int SSL_COMP_add_compression_method(int id, void *cm);
# endif
+/* TLS extensions functions */
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg);
+
+/* Pre-shared secret session resumption functions */
+int SSL_set_session_secret_cb(SSL *s,
+ tls_session_secret_cb_fn tls_session_secret_cb,
+ void *arg);
+
/* BEGIN ERROR CODES */
/*
* The following lines are auto generated by the script mkerr.pl. Any changes
@@ -1977,6 +2007,7 @@ void ERR_load_SSL_strings(void);
# define SSL_F_TLS1_ENC 210
# define SSL_F_TLS1_SETUP_KEY_BLOCK 211
# define SSL_F_WRITE_PENDING 212
+#define SSL_F_SSL_SET_SESSION_TICKET_EXT 213
/* Reason codes. */
# define SSL_R_APP_DATA_IN_HANDSHAKE 100
diff -upr openssl-0.9.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
--- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
@@ -716,6 +716,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
return (s->session_timeout);
}
+#ifndef OPENSSL_NO_TLSEXT
+int SSL_set_session_secret_cb(
+ SSL *s,
+ int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg), void *arg)
+{
+ if (s == NULL)
+ return 0;
+ s->tls_session_secret_cb = tls_session_secret_cb;
+ s->tls_session_secret_cb_arg = arg;
+ return 1;
+}
+
+int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
+ void *arg)
+{
+ if (s == NULL)
+ return 0;
+ s->tls_session_ticket_ext_cb = cb;
+ s->tls_session_ticket_ext_cb_arg = arg;
+ return 1;
+}
+
+int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
+{
+ if (s->version >= TLS1_VERSION) {
+ if (s->tlsext_session_ticket) {
+ OPENSSL_free(s->tlsext_session_ticket);
+ s->tlsext_session_ticket = NULL;
+ }
+
+ s->tlsext_session_ticket = OPENSSL_malloc(
+ sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
+ if (!s->tlsext_session_ticket) {
+ SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (ext_data) {
+ s->tlsext_session_ticket->length = ext_len;
+ s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
+ memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
+ } else {
+ s->tlsext_session_ticket->length = 0;
+ s->tlsext_session_ticket->data = NULL;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* OPENSSL_NO_TLSEXT */
+
typedef struct timeout_param_st {
SSL_CTX *ctx;
long time;
diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
--- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
@@ -108,6 +108,11 @@ int tls1_new(SSL *s)
void tls1_free(SSL *s)
{
+#ifndef OPENSSL_NO_TLSEXT
+ if (s->tlsext_session_ticket) {
+ OPENSSL_free(s->tlsext_session_ticket);
+ }
+#endif
ssl3_free(s);
}
@@ -206,8 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
int ticklen;
if (!s->new_session && s->session && s->session->tlsext_tick)
ticklen = s->session->tlsext_ticklen;
- else
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data) {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data,
+ ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ } else
ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
/*
* Check for enough room 2 for extension type, 2 for len rest for
* ticket
@@ -221,6 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
ret += ticklen;
}
}
+skip_ext:
if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
s->version != DTLS1_VERSION) {
@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
return 0;
renegotiate_seen = 1;
+ } else if (type == TLSEXT_TYPE_session_ticket) {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(s, data, size,
+ s->tls_session_ticket_ext_cb_arg))
+ {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
} else if (type == TLSEXT_TYPE_status_request &&
s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) {
@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
}
tlsext_servername = 1;
} else if (type == TLSEXT_TYPE_session_ticket) {
+ if (s->tls_session_ticket_ext_cb &&
+ !s->tls_session_ticket_ext_cb(
+ s, data, size,
+ s->tls_session_ticket_ext_cb_arg)) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
|| (size > 0)) {
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
@@ -993,6 +1026,14 @@ int tls1_process_ticket(SSL *s, unsigned
s->tlsext_ticket_expected = 1;
return 0; /* Cache miss */
}
+ if (s->tls_session_secret_cb) {
+ /* Indicate cache miss here and instead of
+ * generating the session from ticket now,
+ * trigger abbreviated handshake based on
+ * external mechanism to calculate the master
+ * secret later. */
+ return 0;
+ }
return tls_decrypt_ticket(s, p, size, session_id, len, ret);
}
p += size;
diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
--- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
+++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
@@ -460,6 +460,12 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
# define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"
# endif
+/* TLS extension struct */
+struct tls_session_ticket_ext_st {
+ unsigned short length;
+ void *data;
+};
+
#ifdef __cplusplus
}
#endif
diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
--- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
+++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
SSL_get_servername 291 EXIST::FUNCTION:TLSEXT
SSL_get_servername_type 292 EXIST::FUNCTION:TLSEXT
SSL_CTX_set_client_cert_engine 293 EXIST::FUNCTION:ENGINE
+SSL_set_session_ticket_ext 306 EXIST::FUNCTION:TLSEXT
+SSL_set_session_secret_cb 307 EXIST::FUNCTION:TLSEXT

View File

@ -459,10 +459,14 @@ 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. */
/* Acct-Session-Id should be unique over reboots. Using a random number
* is preferred. If that is not available, take the current time. Mix
* in microseconds to make this more likely to be unique. */
os_get_time(&now);
hapd->acct_session_id_hi = now.sec;
if (os_get_random((u8 *) &hapd->acct_session_id_hi,
sizeof(hapd->acct_session_id_hi)) < 0)
hapd->acct_session_id_hi = now.sec;
hapd->acct_session_id_hi ^= now.usec;
if (radius_client_register(hapd->radius, RADIUS_ACCT,
accounting_receive, hapd))
@ -475,7 +479,7 @@ int accounting_init(struct hostapd_data *hapd)
/**
* accounting_deinit: Deinitilize accounting
* accounting_deinit: Deinitialize accounting
* @hapd: hostapd BSS data
*/
void accounting_deinit(struct hostapd_data *hapd)

View File

@ -479,16 +479,10 @@ static int acs_usable_chan(struct hostapd_channel_data *chan)
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
int *entry;
if (!iface->conf->chanlist)
if (!iface->conf->acs_ch_list.num)
return 1;
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
if (*entry == chan->chan)
return 1;
}
return 0;
return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}
@ -900,6 +894,9 @@ static int acs_request_scan(struct hostapd_iface *iface)
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (!is_in_chanlist(iface, chan))
continue;
*freq++ = chan->freq;
}
*freq = 0;

View File

@ -172,6 +172,7 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->ap_table_max_size = 255;
conf->ap_table_expiration_time = 60;
conf->track_sta_max_age = 180;
#ifdef CONFIG_TESTING_OPTIONS
conf->ignore_probe_probability = 0.0;
@ -181,6 +182,8 @@ struct hostapd_config * hostapd_config_defaults(void)
conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
conf->acs = 0;
conf->acs_ch_list.num = 0;
#ifdef CONFIG_ACS
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
@ -559,6 +562,13 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
os_free(conf->server_id);
#ifdef CONFIG_TESTING_OPTIONS
wpabuf_free(conf->own_ie_override);
#endif /* CONFIG_TESTING_OPTIONS */
os_free(conf->no_probe_resp_if_seen_on);
os_free(conf->no_auth_if_seen_on);
os_free(conf);
}
@ -579,7 +589,7 @@ void hostapd_config_free(struct hostapd_config *conf)
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
os_free(conf->chanlist);
os_free(conf->acs_ch_list.range);
os_free(conf->driver_params);
#ifdef CONFIG_ACS
os_free(conf->acs_chan_bias);
@ -817,9 +827,9 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
if (full_config && bss->wps_state && bss->wpa &&
(!(bss->wpa & 2) ||
!(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
"WPA2/CCMP forced WPS to be disabled");
"WPA2/CCMP/GCMP forced WPS to be disabled");
bss->wps_state = 0;
}
#endif /* CONFIG_WPS */
@ -841,6 +851,29 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
}
static int hostapd_config_check_cw(struct hostapd_config *conf, int queue)
{
int tx_cwmin = conf->tx_queue[queue].cwmin;
int tx_cwmax = conf->tx_queue[queue].cwmax;
int ac_cwmin = conf->wmm_ac_params[queue].cwmin;
int ac_cwmax = conf->wmm_ac_params[queue].cwmax;
if (tx_cwmin > tx_cwmax) {
wpa_printf(MSG_ERROR,
"Invalid TX queue cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)",
tx_cwmin, tx_cwmax);
return -1;
}
if (ac_cwmin > ac_cwmax) {
wpa_printf(MSG_ERROR,
"Invalid WMM AC cwMin/cwMax values. cwMin(%d) greater than cwMax(%d)",
ac_cwmin, ac_cwmax);
return -1;
}
return 0;
}
int hostapd_config_check(struct hostapd_config *conf, int full_config)
{
size_t i;
@ -870,6 +903,11 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config)
return -1;
}
for (i = 0; i < NUM_TX_QUEUES; i++) {
if (hostapd_config_check_cw(conf, i))
return -1;
}
for (i = 0; i < conf->num_bss; i++) {
if (hostapd_config_check_bss(conf->bss[i], conf, full_config))
return -1;
@ -937,10 +975,11 @@ void hostapd_set_security_params(struct hostapd_bss_config *bss,
bss->rsn_pairwise = WPA_CIPHER_CCMP;
} else {
bss->ssid.security_policy = SECURITY_PLAINTEXT;
bss->wpa_group = WPA_CIPHER_NONE;
bss->wpa_pairwise = WPA_CIPHER_NONE;
bss->rsn_pairwise = WPA_CIPHER_NONE;
if (full_config)
if (full_config) {
bss->wpa_group = WPA_CIPHER_NONE;
bss->wpa_pairwise = WPA_CIPHER_NONE;
bss->rsn_pairwise = WPA_CIPHER_NONE;
bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
}
}
}

View File

@ -1,6 +1,6 @@
/*
* hostapd / Configuration definitions and helpers functions
* Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -12,8 +12,10 @@
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#include "fst/fst.h"
/**
* mesh_conf - local MBSS state and settings
@ -31,8 +33,8 @@ struct mesh_conf {
u8 mesh_sp_id;
/* Authentication Protocol Identifier */
u8 mesh_auth_id;
u8 *ies;
int ie_len;
u8 *rsn_ie;
int rsn_ie_len;
#define MESH_CONF_SEC_NONE BIT(0)
#define MESH_CONF_SEC_AUTH BIT(1)
#define MESH_CONF_SEC_AMPE BIT(2)
@ -57,8 +59,6 @@ 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;
@ -78,7 +78,7 @@ typedef enum hostap_security_policy {
} secpolicy;
struct hostapd_ssid {
u8 ssid[HOSTAPD_MAX_SSID_LEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
@ -114,12 +114,10 @@ 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 configured;
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 */
@ -332,6 +330,7 @@ struct hostapd_bss_config {
char *private_key;
char *private_key_passwd;
int check_crl;
unsigned int tls_session_lifetime;
char *ocsp_stapling_response;
char *dh_file;
char *openssl_ciphers;
@ -490,6 +489,7 @@ struct hostapd_bss_config {
int osen;
int proxy_arp;
int na_mcast_to_ucast;
#ifdef CONFIG_HS20
int hs20;
int disable_dgaf;
@ -510,7 +510,7 @@ struct hostapd_bss_config {
char file[256];
} *hs20_icons;
size_t hs20_icons_count;
u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
u8 osu_ssid[SSID_MAX_LEN];
size_t osu_ssid_len;
struct hs20_osu_provider {
unsigned int friendly_name_count;
@ -545,6 +545,7 @@ struct hostapd_bss_config {
#ifdef CONFIG_TESTING_OPTIONS
u8 bss_load_test[5];
u8 bss_load_test_set;
struct wpabuf *own_ie_override;
#endif /* CONFIG_TESTING_OPTIONS */
#define MESH_ENABLED BIT(0)
@ -553,6 +554,9 @@ struct hostapd_bss_config {
int radio_measurements;
int vendor_vht;
char *no_probe_resp_if_seen_on;
char *no_auth_if_seen_on;
};
@ -568,7 +572,8 @@ struct hostapd_config {
int fragm_threshold;
u8 send_probe_response;
u8 channel;
int *chanlist;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
@ -584,6 +589,9 @@ struct hostapd_config {
int ap_table_max_size;
int ap_table_expiration_time;
unsigned int track_sta_max_num;
unsigned int track_sta_max_age;
char country[3]; /* first two octets: country code as described in
* ISO/IEC 3166-1. Third octet:
* ' ' (ascii 32): all environments
@ -620,6 +628,7 @@ struct hostapd_config {
u16 ht_capab;
int ieee80211n;
int secondary_channel;
int no_pri_sec_switch;
int require_ht;
int obss_interval;
u32 vht_capab;
@ -629,6 +638,10 @@ struct hostapd_config {
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
#ifdef CONFIG_FST
struct fst_iface_cfg fst_cfg;
#endif /* CONFIG_FST */
#ifdef CONFIG_P2P
u8 p2p_go_ctwindow;
#endif /* CONFIG_P2P */

View File

@ -81,6 +81,22 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
wpabuf_put_data(proberesp, buf, pos - buf);
}
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
size_t add = wpabuf_len(hapd->iface->fst_ies);
if (wpabuf_resize(&beacon, add) < 0)
goto fail;
wpabuf_put_buf(beacon, hapd->iface->fst_ies);
if (wpabuf_resize(&proberesp, add) < 0)
goto fail;
wpabuf_put_buf(proberesp, hapd->iface->fst_ies);
if (wpabuf_resize(&assocresp, add) < 0)
goto fail;
wpabuf_put_buf(assocresp, hapd->iface->fst_ies);
}
#endif /* CONFIG_FST */
if (hapd->wps_beacon_ie) {
if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
0)
@ -217,6 +233,15 @@ void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
}
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
{
if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
return 0;
return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
}
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
{
struct wpabuf *beacon, *proberesp, *assocresp;
@ -281,8 +306,14 @@ int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
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 |
hapd->conf->rsn_pairwise;
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
(WPA_PROTO_WPA | WPA_PROTO_RSN))
params.wpa_pairwise = hapd->conf->wpa_pairwise |
hapd->conf->rsn_pairwise;
else if (hapd->conf->wpa & WPA_PROTO_RSN)
params.wpa_pairwise = hapd->conf->rsn_pairwise;
else if (hapd->conf->wpa & WPA_PROTO_WPA)
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
@ -618,7 +649,7 @@ int hostapd_drv_send_mlme(struct hostapd_data *hapd,
{
if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
return 0;
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack, 0);
}
@ -712,16 +743,100 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
}
static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
struct hostapd_hw_modes *mode,
int acs_ch_list_all,
int **freq_list)
{
int i;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if ((acs_ch_list_all ||
freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
chan->chan)) &&
!(chan->flag & HOSTAPD_CHAN_DISABLED))
int_array_add_unique(freq_list, chan->freq);
}
}
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
int ret, i, acs_ch_list_all = 0;
u8 *channels = NULL;
unsigned int num_channels = 0;
struct hostapd_hw_modes *mode;
int *freq_list = NULL;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
os_memset(&params, 0, sizeof(params));
params.hw_mode = hapd->iface->conf->hw_mode;
/*
* If no chanlist config parameter is provided, include all enabled
* channels of the selected hw_mode.
*/
if (!hapd->iface->conf->acs_ch_list.num)
acs_ch_list_all = 1;
mode = hapd->iface->current_mode;
if (mode) {
channels = os_malloc(mode->num_channels);
if (channels == NULL)
return -1;
for (i = 0; i < mode->num_channels; i++) {
struct hostapd_channel_data *chan = &mode->channels[i];
if (!acs_ch_list_all &&
!freq_range_list_includes(
&hapd->iface->conf->acs_ch_list,
chan->chan))
continue;
if (!(chan->flag & HOSTAPD_CHAN_DISABLED)) {
channels[num_channels++] = chan->chan;
int_array_add_unique(&freq_list, chan->freq);
}
}
} else {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
mode = &hapd->iface->hw_features[i];
hostapd_get_hw_mode_any_channels(hapd, mode,
acs_ch_list_all,
&freq_list);
}
}
params.ch_list = channels;
params.ch_list_len = num_channels;
params.freq_list = freq_list;
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
return hapd->driver->do_acs(hapd->drv_priv, &params);
params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
params.ch_width = 20;
if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
params.ch_width = 40;
/* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
*/
if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
params.ch_width = 80;
else if (hapd->iface->conf->vht_oper_chwidth ==
VHT_CHANWIDTH_160MHZ ||
hapd->iface->conf->vht_oper_chwidth ==
VHT_CHANWIDTH_80P80MHZ)
params.ch_width = 160;
}
ret = hapd->driver->do_acs(hapd->drv_priv, &params);
os_free(channels);
return ret;
}

View File

@ -24,6 +24,7 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
struct wpabuf *proberesp,
struct wpabuf *assocresp);
int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);

View File

@ -193,14 +193,14 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
if (elems->erp_info && elems->erp_info_len == 1)
if (elems->erp_info)
ap->erp = elems->erp_info[0];
else
ap->erp = -1;
if (elems->ds_params && elems->ds_params_len == 1)
if (elems->ds_params)
ap->channel = elems->ds_params[0];
else if (elems->ht_operation && elems->ht_operation_len >= 1)
else if (elems->ht_operation)
ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
@ -248,15 +248,12 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
}
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
void ap_list_timer(struct hostapd_iface *iface)
{
struct hostapd_iface *iface = eloop_ctx;
struct os_reltime now;
struct ap_info *ap;
int set_beacon = 0;
eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
if (!iface->ap_list)
return;
@ -305,13 +302,11 @@ static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
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

@ -39,6 +39,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
#ifdef NEED_AP_MLME
int ap_list_init(struct hostapd_iface *iface);
void ap_list_deinit(struct hostapd_iface *iface);
void ap_list_timer(struct hostapd_iface *iface);
#else /* NEED_AP_MLME */
static inline int ap_list_init(struct hostapd_iface *iface)
{
@ -48,6 +49,10 @@ static inline int ap_list_init(struct hostapd_iface *iface)
static inline void ap_list_deinit(struct hostapd_iface *iface)
{
}
static inline void ap_list_timer(struct hostapd_iface *iface)
{
}
#endif /* NEED_AP_MLME */
#endif /* AP_LIST_H */

View File

@ -55,10 +55,11 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
{
const struct hostapd_eap_user *eap_user;
int i;
int rv = -1;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
goto out;
if (user == NULL)
return 0;
@ -72,7 +73,7 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
return -1;
goto out;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
@ -83,8 +84,13 @@ static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
rv = 0;
return 0;
out:
if (rv)
wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
return rv;
}
@ -126,6 +132,7 @@ static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
#endif /* CONFIG_HS20 */
srv.erp = conf->eap_server_erp;
srv.erp_domain = conf->erp_domain;
srv.tls_session_lifetime = conf->tls_session_lifetime;
hapd->radius_srv = radius_server_init(&srv);
if (hapd->radius_srv == NULL) {
@ -145,9 +152,12 @@ int authsrv_init(struct hostapd_data *hapd)
if (hapd->conf->eap_server &&
(hapd->conf->ca_cert || hapd->conf->server_cert ||
hapd->conf->private_key || hapd->conf->dh_file)) {
struct tls_config conf;
struct tls_connection_params params;
hapd->ssl_ctx = tls_init(NULL);
os_memset(&conf, 0, sizeof(conf));
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
hapd->ssl_ctx = tls_init(&conf);
if (hapd->ssl_ctx == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize TLS");
authsrv_deinit(hapd);

View File

@ -360,7 +360,6 @@ static u8 * hostapd_add_csa_elems(struct hostapd_data *hapd, u8 *pos,
static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
struct sta_info *sta,
const struct ieee80211_mgmt *req,
int is_p2p, size_t *resp_len)
{
@ -378,6 +377,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
if (hapd->p2p_probe_resp_ie)
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
#endif /* CONFIG_P2P */
#ifdef CONFIG_FST
if (hapd->iface->fst_ies)
buflen += wpabuf_len(hapd->iface->fst_ies);
#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
if (hapd->conf->vendor_vht) {
@ -402,7 +405,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
/* 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));
host_to_le16(hostapd_own_capab_info(hapd));
pos = resp->u.probe_resp.variable;
*pos++ = WLAN_EID_SSID;
@ -450,6 +453,15 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
&hapd->cs_c_off_proberesp);
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
os_memcpy(pos, wpabuf_head(hapd->iface->fst_ies),
wpabuf_len(hapd->iface->fst_ies));
pos += wpabuf_len(hapd->iface->fst_ies);
}
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
pos = hostapd_eid_vht_capabilities(hapd, pos);
@ -540,6 +552,102 @@ static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
}
void sta_track_expire(struct hostapd_iface *iface, int force)
{
struct os_reltime now;
struct hostapd_sta_info *info;
if (!iface->num_sta_seen)
return;
os_get_reltime(&now);
while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
list))) {
if (!force &&
!os_reltime_expired(&now, &info->last_seen,
iface->conf->track_sta_max_age))
break;
force = 0;
wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for "
MACSTR, iface->bss[0]->conf->iface,
MAC2STR(info->addr));
dl_list_del(&info->list);
iface->num_sta_seen--;
os_free(info);
}
}
static struct hostapd_sta_info * sta_track_get(struct hostapd_iface *iface,
const u8 *addr)
{
struct hostapd_sta_info *info;
dl_list_for_each(info, &iface->sta_seen, struct hostapd_sta_info, list)
if (os_memcmp(addr, info->addr, ETH_ALEN) == 0)
return info;
return NULL;
}
void sta_track_add(struct hostapd_iface *iface, const u8 *addr)
{
struct hostapd_sta_info *info;
info = sta_track_get(iface, addr);
if (info) {
/* Move the most recent entry to the end of the list */
dl_list_del(&info->list);
dl_list_add_tail(&iface->sta_seen, &info->list);
os_get_reltime(&info->last_seen);
return;
}
/* Add a new entry */
info = os_zalloc(sizeof(*info));
os_memcpy(info->addr, addr, ETH_ALEN);
os_get_reltime(&info->last_seen);
if (iface->num_sta_seen >= iface->conf->track_sta_max_num) {
/* Expire oldest entry to make room for a new one */
sta_track_expire(iface, 1);
}
wpa_printf(MSG_MSGDUMP, "%s: Add STA tracking entry for "
MACSTR, iface->bss[0]->conf->iface, MAC2STR(addr));
dl_list_add_tail(&iface->sta_seen, &info->list);
iface->num_sta_seen++;
}
struct hostapd_data *
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
const char *ifname)
{
struct hapd_interfaces *interfaces = iface->interfaces;
size_t i, j;
for (i = 0; i < interfaces->count; i++) {
struct hostapd_data *hapd = NULL;
iface = interfaces->iface[i];
for (j = 0; j < iface->num_bss; j++) {
hapd = iface->bss[j];
if (os_strcmp(ifname, hapd->conf->iface) == 0)
break;
hapd = NULL;
}
if (hapd && sta_track_get(iface, addr))
return hapd;
}
return NULL;
}
void handle_probe_req(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, size_t len,
int ssi_signal)
@ -548,7 +656,6 @@ void handle_probe_req(struct hostapd_data *hapd,
struct ieee802_11_elems elems;
const u8 *ie;
size_t ie_len;
struct sta_info *sta = NULL;
size_t i, resp_len;
int noack;
enum ssid_match_result res;
@ -556,6 +663,8 @@ void handle_probe_req(struct hostapd_data *hapd,
ie = mgmt->u.probe_req.variable;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
return;
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa);
ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
@ -590,7 +699,7 @@ void handle_probe_req(struct hostapd_data *hapd,
* is less likely to see them (Probe Request frame sent on a
* neighboring, but partially overlapping, channel).
*/
if (elems.ds_params && elems.ds_params_len == 1 &&
if (elems.ds_params &&
hapd->iface->current_mode &&
(hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
@ -635,8 +744,6 @@ void handle_probe_req(struct hostapd_data *hapd,
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 &&
@ -649,10 +756,7 @@ void handle_probe_req(struct hostapd_data *hapd,
res = ssid_match(hapd, elems.ssid, elems.ssid_len,
elems.ssid_list, elems.ssid_list_len);
if (res != NO_SSID_MATCH) {
if (sta)
sta->ssid_probe = &hapd->conf->ssid;
} else {
if (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
@ -709,6 +813,18 @@ void handle_probe_req(struct hostapd_data *hapd,
/* TODO: verify that supp_rates contains at least one matching rate
* with AP configuration */
if (hapd->conf->no_probe_resp_if_seen_on &&
is_multicast_ether_addr(mgmt->da) &&
is_multicast_ether_addr(mgmt->bssid) &&
sta_track_seen_on(hapd->iface, mgmt->sa,
hapd->conf->no_probe_resp_if_seen_on)) {
wpa_printf(MSG_MSGDUMP, "%s: Ignore Probe Request from " MACSTR
" since STA has been seen on %s",
hapd->conf->iface, MAC2STR(mgmt->sa),
hapd->conf->no_probe_resp_if_seen_on);
return;
}
#ifdef CONFIG_TESTING_OPTIONS
if (hapd->iconf->ignore_probe_probability > 0.0 &&
drand48() < hapd->iconf->ignore_probe_probability) {
@ -719,7 +835,7 @@ void handle_probe_req(struct hostapd_data *hapd,
}
#endif /* CONFIG_TESTING_OPTIONS */
resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
return;
@ -774,7 +890,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
"this");
/* Generate a Probe Response template for the non-P2P case */
return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
}
#endif /* NEED_AP_MLME */
@ -804,6 +920,10 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
if (hapd->p2p_beacon_ie)
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
#endif /* CONFIG_P2P */
#ifdef CONFIG_FST
if (hapd->iface->fst_ies)
tail_len += wpabuf_len(hapd->iface->fst_ies);
#endif /* CONFIG_FST */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
@ -833,7 +953,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
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);
capab_info = hostapd_own_capab_info(hapd);
head->u.beacon.capab_info = host_to_le16(capab_info);
pos = &head->u.beacon.variable[0];
@ -902,6 +1022,15 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
&hapd->cs_c_off_beacon);
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
os_memcpy(tailpos, wpabuf_head(hapd->iface->fst_ies),
wpabuf_len(hapd->iface->fst_ies));
tailpos += wpabuf_len(hapd->iface->fst_ies);
}
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
@ -963,8 +1092,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
params->basic_rates = hapd->iface->basic_rates;
params->ssid = hapd->conf->ssid.ssid;
params->ssid_len = hapd->conf->ssid.ssid_len;
params->pairwise_ciphers = hapd->conf->wpa_pairwise |
hapd->conf->rsn_pairwise;
if ((hapd->conf->wpa & (WPA_PROTO_WPA | WPA_PROTO_RSN)) ==
(WPA_PROTO_WPA | WPA_PROTO_RSN))
params->pairwise_ciphers = hapd->conf->wpa_pairwise |
hapd->conf->rsn_pairwise;
else if (hapd->conf->wpa & WPA_PROTO_RSN)
params->pairwise_ciphers = hapd->conf->rsn_pairwise;
else if (hapd->conf->wpa & WPA_PROTO_WPA)
params->pairwise_ciphers = hapd->conf->wpa_pairwise;
params->group_cipher = hapd->conf->wpa_group;
params->key_mgmt_suites = hapd->conf->wpa_key_mgmt;
params->auth_algs = hapd->conf->auth_algs;

View File

@ -21,5 +21,10 @@ int ieee802_11_update_beacons(struct hostapd_iface *iface);
int ieee802_11_build_ap_params(struct hostapd_data *hapd,
struct wpa_driver_ap_params *params);
void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params);
void sta_track_add(struct hostapd_iface *iface, const u8 *addr);
void sta_track_expire(struct hostapd_iface *iface, int force);
struct hostapd_data *
sta_track_seen_on(struct hostapd_iface *iface, const u8 *addr,
const char *ifname);
#endif /* BEACON_H */

View File

@ -12,6 +12,7 @@
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "fst/fst_ctrl_iface.h"
#include "hostapd.h"
#include "ieee802_1x.h"
#include "wpa_auth.h"
@ -153,6 +154,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
}
#endif /* CONFIG_SAE */
if (sta->vlan_id > 0) {
res = os_snprintf(buf + len, buflen - len, "vlan_id=%d\n",
sta->vlan_id);
if (!os_snprintf_error(buflen - len, res))
len += res;
}
return len;
}
@ -199,7 +207,10 @@ int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
return -1;
}
return hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
ret = hostapd_ctrl_iface_sta_mib(hapd, sta, buf, buflen);
ret += fst_ctrl_iface_mb_info(addr, buf + ret, buflen - ret);
return ret;
}

View File

@ -122,6 +122,20 @@ static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
}
static struct hostapd_channel_data *
dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
{
int i;
for (i = first_chan_idx; i < mode->num_channels; i++) {
if (mode->channels[i].freq == freq)
return &mode->channels[i];
}
return NULL;
}
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
int skip_radar)
@ -129,15 +143,15 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *first_chan, *chan;
int i;
if (first_chan_idx + num_chans >= mode->num_channels)
if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
for (i = 0; i < num_chans; i++) {
chan = &mode->channels[first_chan_idx + i];
if (first_chan->freq + i * 20 != chan->freq)
chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
first_chan_idx);
if (!chan)
return 0;
if (!dfs_channel_available(chan, skip_radar))
@ -151,16 +165,10 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
int *entry;
if (!iface->conf->chanlist)
if (!iface->conf->acs_ch_list.num)
return 1;
for (entry = iface->conf->chanlist; *entry != -1; entry++) {
if (*entry == chan->chan)
return 1;
}
return 0;
return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}

View File

@ -18,6 +18,7 @@
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
#include "fst/fst.h"
#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
@ -42,10 +43,10 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
#ifdef CONFIG_IEEE80211R
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
u8 *p = buf;
#endif /* CONFIG_IEEE80211R */
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
u16 reason = WLAN_REASON_UNSPECIFIED;
u16 status = WLAN_STATUS_SUCCESS;
const u8 *p2p_dev_addr = NULL;
@ -58,8 +59,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
* running, so better make sure we stop processing such an
* event here.
*/
wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
"no address");
wpa_printf(MSG_DEBUG,
"hostapd_notif_assoc: Skip event with no address");
return -1;
}
random_add_randomness(addr, ETH_ALEN);
@ -89,8 +90,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
} else {
ie = NULL;
ielen = 0;
wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
"(Re)AssocReq");
wpa_printf(MSG_DEBUG,
"STA did not include WPS/RSN/WPA IE in (Re)AssocReq");
}
sta = ap_get_sta(hapd, addr);
@ -126,8 +127,6 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
elems.ht_capabilities_len >=
sizeof(struct ieee80211_ht_capabilities) &&
(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
struct ieee80211_ht_capabilities *ht_cap =
@ -157,13 +156,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
wpabuf_free(sta->mb_ies);
if (hapd->iface->fst)
sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
else
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
if (hapd->conf->wpa) {
if (ie == NULL || ielen == 0) {
#ifdef CONFIG_WPS
if (hapd->conf->wps_state) {
wpa_printf(MSG_DEBUG, "STA did not include "
"WPA/RSN IE in (Re)Association "
"Request - possible WPS use");
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;
}
@ -176,13 +182,14 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
struct wpabuf *wps;
sta->flags |= WLAN_STA_WPS;
wps = ieee802_11_vendor_ie_concat(ie, ielen,
WPS_IE_VENDOR_TYPE);
if (wps) {
if (wps_is_20(wps)) {
wpa_printf(MSG_DEBUG, "WPS: STA "
"supports WPS 2.0");
wpa_printf(MSG_DEBUG,
"WPS: STA supports WPS 2.0");
sta->flags |= WLAN_STA_WPS2;
}
wpabuf_free(wps);
@ -196,16 +203,17 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->addr,
p2p_dev_addr);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
"machine");
wpa_printf(MSG_ERROR,
"Failed to initialize WPA state machine");
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
ie, ielen,
elems.mdie, elems.mdie_len);
if (res != WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "WPA/RSN information element "
"rejected? (res %u)", res);
wpa_printf(MSG_DEBUG,
"WPA/RSN information element rejected? (res %u)",
res);
wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
if (res == WPA_INVALID_GROUP) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
@ -248,14 +256,12 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (sta->sa_query_count == 0)
ap_sta_start_sa_query(hapd, sta);
#ifdef CONFIG_IEEE80211R
status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
p - buf);
#endif /* CONFIG_IEEE80211R */
return 0;
}
@ -283,6 +289,7 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
if (req_ies)
wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
WPS_IE_VENDOR_TYPE);
@ -299,8 +306,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
if (wps) {
sta->flags |= WLAN_STA_WPS;
if (wps_is_20(wps)) {
wpa_printf(MSG_DEBUG, "WPS: STA supports "
"WPS 2.0");
wpa_printf(MSG_DEBUG,
"WPS: STA supports WPS 2.0");
sta->flags |= WLAN_STA_WPS2;
}
} else
@ -322,8 +329,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr, NULL);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_WARNING, "Failed to initialize WPA "
"state machine");
wpa_printf(MSG_WARNING,
"Failed to initialize WPA state machine");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
if (wpa_validate_osen(hapd->wpa_auth, sta->wpa_sm,
@ -395,8 +402,8 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
* 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");
wpa_printf(MSG_DEBUG,
"hostapd_notif_disassoc: Skip event with no address");
return;
}
@ -405,8 +412,9 @@ void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
sta = ap_get_sta(hapd, addr);
if (sta == NULL) {
wpa_printf(MSG_DEBUG, "Disassociation notification for "
"unknown STA " MACSTR, MAC2STR(addr));
wpa_printf(MSG_DEBUG,
"Disassociation notification for unknown STA "
MACSTR, MAC2STR(addr));
return;
}
@ -427,8 +435,8 @@ void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
return;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
"missing ACKs");
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);
@ -452,8 +460,8 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
channel = hostapd_hw_get_channel(hapd, freq);
if (!channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING, "driver switched to "
"bad channel!");
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel!");
return;
}
@ -532,10 +540,9 @@ void hostapd_event_connect_failed_reason(struct hostapd_data *hapd,
#ifdef CONFIG_ACS
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
u8 pri_channel, u8 sec_channel)
struct acs_selected_channels *acs_res)
{
int channel;
int ret;
int ret, i;
if (hapd->iconf->channel) {
wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
@ -543,29 +550,73 @@ static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
return;
}
hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
if (!hapd->iface->current_mode) {
for (i = 0; i < hapd->iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode =
&hapd->iface->hw_features[i];
channel = pri_channel;
if (!channel) {
if (mode->mode == acs_res->hw_mode) {
hapd->iface->current_mode = mode;
break;
}
}
if (!hapd->iface->current_mode) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver selected to bad hw_mode");
return;
}
}
hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
if (!acs_res->pri_channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
return;
}
hapd->iconf->channel = channel;
hapd->iconf->channel = acs_res->pri_channel;
hapd->iconf->acs = 1;
if (sec_channel == 0)
if (acs_res->sec_channel == 0)
hapd->iconf->secondary_channel = 0;
else if (sec_channel < pri_channel)
else if (acs_res->sec_channel < acs_res->pri_channel)
hapd->iconf->secondary_channel = -1;
else if (sec_channel > pri_channel)
else if (acs_res->sec_channel > acs_res->pri_channel)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
return;
}
if (hapd->iface->conf->ieee80211ac) {
/* set defaults for backwards compatibility */
hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
if (acs_res->ch_width == 80) {
hapd->iconf->vht_oper_centr_freq_seg0_idx =
acs_res->vht_seg0_center_ch;
hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
} else if (acs_res->ch_width == 160) {
if (acs_res->vht_seg1_center_ch == 0) {
hapd->iconf->vht_oper_centr_freq_seg0_idx =
acs_res->vht_seg0_center_ch;
hapd->iconf->vht_oper_chwidth =
VHT_CHANWIDTH_160MHZ;
} else {
hapd->iconf->vht_oper_centr_freq_seg0_idx =
acs_res->vht_seg0_center_ch;
hapd->iconf->vht_oper_centr_freq_seg1_idx =
acs_res->vht_seg1_center_ch;
hapd->iconf->vht_oper_chwidth =
VHT_CHANWIDTH_80P80MHZ;
}
}
}
ret = hostapd_acs_completed(hapd->iface, 0);
if (ret) {
wpa_printf(MSG_ERROR,
@ -647,8 +698,8 @@ static void hostapd_notif_auth(struct hostapd_data *hapd,
sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
sta->addr, NULL);
if (sta->wpa_sm == NULL) {
wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
"state machine");
wpa_printf(MSG_DEBUG,
"FT: Failed to initialize WPA state machine");
status = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
@ -683,7 +734,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
if (WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION)
return; /* handled by the driver */
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
mgmt->u.action.category, (int) plen);
sta = ap_get_sta(hapd, mgmt->sa);
@ -694,6 +745,7 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211R
if (mgmt->u.action.category == WLAN_ACTION_FT) {
const u8 *payload = drv_mgmt->frame + 24 + 1;
wpa_ft_action_rx(sta->wpa_sm, payload, plen);
}
#endif /* CONFIG_IEEE80211R */
@ -710,6 +762,13 @@ static void hostapd_action_rx(struct hostapd_data *hapd,
ieee802_11_rx_wnm_action_ap(hapd, mgmt, drv_mgmt->frame_len);
}
#endif /* CONFIG_WNM */
#ifdef CONFIG_FST
if (mgmt->u.action.category == WLAN_ACTION_FST && hapd->iface->fst) {
fst_rx_action(hapd->iface->fst, mgmt, drv_mgmt->frame_len);
return;
}
#endif /* CONFIG_FST */
}
@ -761,6 +820,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
if (hapd->ext_mgmt_frame_handling) {
size_t hex_len = 2 * rx_mgmt->frame_len + 1;
char *hex = os_malloc(hex_len);
if (hex) {
wpa_snprintf_hex(hex, hex_len, rx_mgmt->frame,
rx_mgmt->frame_len);
@ -778,8 +838,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
hapd = get_hapd_bssid(iface, bssid);
if (hapd == NULL) {
u16 fc;
fc = le_to_host16(hdr->frame_control);
u16 fc = le_to_host16(hdr->frame_control);
/*
* Drop frames to unknown BSSIDs except for Beacon frames which
@ -798,6 +857,7 @@ static int hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
if (hapd == HAPD_BROADCAST) {
size_t i;
ret = 0;
for (i = 0; i < iface->num_bss; i++) {
/* if bss is set, driver will call this function for
@ -824,6 +884,7 @@ 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)
@ -837,6 +898,7 @@ static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
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;
@ -863,11 +925,10 @@ static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
size_t j;
for (j = 0; j < iface->num_bss; j++) {
if ((sta = ap_get_sta(iface->bss[j], src))) {
if (sta->flags & WLAN_STA_ASSOC) {
hapd = iface->bss[j];
break;
}
sta = ap_get_sta(iface->bss[j], src);
if (sta && sta->flags & WLAN_STA_ASSOC) {
hapd = iface->bss[j];
break;
}
}
@ -927,7 +988,8 @@ static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
return;
wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
wpa_printf(MSG_DEBUG,
"Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
survey->freq,
(unsigned long int) survey->channel_time,
(unsigned long int) survey->channel_time_busy);
@ -1061,6 +1123,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
fc = le_to_host16(hdr->frame_control);
if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@ -1248,9 +1311,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
break;
#ifdef CONFIG_ACS
case EVENT_ACS_CHANNEL_SELECTED:
hostapd_acs_channel_selected(
hapd, data->acs_selected_channels.pri_channel,
data->acs_selected_channels.sec_channel);
hostapd_acs_channel_selected(hapd,
&data->acs_selected_channels);
break;
#endif /* CONFIG_ACS */
default:

View File

@ -138,8 +138,12 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
char id_str[256], cmd[300];
size_t i;
if (identity_len >= sizeof(id_str))
if (identity_len >= sizeof(id_str)) {
wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
__func__, (int) identity_len,
(int) (sizeof(id_str)));
return NULL;
}
os_memcpy(id_str, identity, identity_len);
id_str[identity_len] = '\0';
for (i = 0; i < identity_len; i++) {
@ -182,7 +186,9 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
SQLITE_OK) {
wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
wpa_printf(MSG_DEBUG,
"DB: Failed to complete SQL operation: %s db: %s",
sqlite3_errmsg(db), hapd->conf->eap_user_sqlite);
} else if (hapd->tmp_eap_user.next)
user = &hapd->tmp_eap_user;
@ -192,8 +198,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
wpa_printf(MSG_DEBUG, "DB: %s", cmd);
if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
NULL) != SQLITE_OK) {
wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
"operation");
wpa_printf(MSG_DEBUG,
"DB: Failed to complete SQL operation: %s db: %s",
sqlite3_errmsg(db),
hapd->conf->eap_user_sqlite);
} else if (hapd->tmp_eap_user.next) {
user = &hapd->tmp_eap_user;
os_free(user->identity);

View File

@ -17,6 +17,7 @@
#include "eap_server/tncs.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "fst/fst.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
@ -179,6 +180,7 @@ int hostapd_reload_config(struct hostapd_iface *iface)
hapd = iface->bss[j];
hapd->iconf = newconf;
hapd->iconf->channel = oldconf->channel;
hapd->iconf->acs = oldconf->acs;
hapd->iconf->secondary_channel = oldconf->secondary_channel;
hapd->iconf->ieee80211n = oldconf->ieee80211n;
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
@ -259,6 +261,7 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
hapd->probereq_cb = NULL;
hapd->num_probereq_cb = 0;
#ifdef CONFIG_P2P
wpabuf_free(hapd->p2p_beacon_ie);
@ -353,6 +356,22 @@ static void hostapd_cleanup(struct hostapd_data *hapd)
}
static void sta_track_deinit(struct hostapd_iface *iface)
{
struct hostapd_sta_info *info;
if (!iface->num_sta_seen)
return;
while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info,
list))) {
dl_list_del(&info->list);
iface->num_sta_seen--;
os_free(info);
}
}
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
@ -368,6 +387,7 @@ static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
os_free(iface->basic_rates);
iface->basic_rates = NULL;
ap_list_deinit(iface);
sta_track_deinit(iface);
}
@ -861,7 +881,7 @@ hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
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];
u8 ssid[SSID_MAX_LEN + 1];
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
@ -1363,6 +1383,132 @@ fail:
}
#ifdef CONFIG_FST
static const u8 * fst_hostapd_get_bssid_cb(void *ctx)
{
struct hostapd_data *hapd = ctx;
return hapd->own_addr;
}
static void fst_hostapd_get_channel_info_cb(void *ctx,
enum hostapd_hw_mode *hw_mode,
u8 *channel)
{
struct hostapd_data *hapd = ctx;
*hw_mode = ieee80211_freq_to_chan(hapd->iface->freq, channel);
}
static void fst_hostapd_set_ies_cb(void *ctx, const struct wpabuf *fst_ies)
{
struct hostapd_data *hapd = ctx;
if (hapd->iface->fst_ies != fst_ies) {
hapd->iface->fst_ies = fst_ies;
if (ieee802_11_set_beacon(hapd))
wpa_printf(MSG_WARNING, "FST: Cannot set beacon");
}
}
static int fst_hostapd_send_action_cb(void *ctx, const u8 *da,
struct wpabuf *buf)
{
struct hostapd_data *hapd = ctx;
return hostapd_drv_send_action(hapd, hapd->iface->freq, 0, da,
wpabuf_head(buf), wpabuf_len(buf));
}
static const struct wpabuf * fst_hostapd_get_mb_ie_cb(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
return sta ? sta->mb_ies : NULL;
}
static void fst_hostapd_update_mb_ie_cb(void *ctx, const u8 *addr,
const u8 *buf, size_t size)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
if (sta) {
struct mb_ies_info info;
if (!mb_ies_info_by_ies(&info, buf, size)) {
wpabuf_free(sta->mb_ies);
sta->mb_ies = mb_ies_by_info(&info);
}
}
}
static const u8 * fst_hostapd_get_sta(struct fst_get_peer_ctx **get_ctx,
Boolean mb_only)
{
struct sta_info *s = (struct sta_info *) *get_ctx;
if (mb_only) {
for (; s && !s->mb_ies; s = s->next)
;
}
if (s) {
*get_ctx = (struct fst_get_peer_ctx *) s->next;
return s->addr;
}
*get_ctx = NULL;
return NULL;
}
static const u8 * fst_hostapd_get_peer_first(void *ctx,
struct fst_get_peer_ctx **get_ctx,
Boolean mb_only)
{
struct hostapd_data *hapd = ctx;
*get_ctx = (struct fst_get_peer_ctx *) hapd->sta_list;
return fst_hostapd_get_sta(get_ctx, mb_only);
}
static const u8 * fst_hostapd_get_peer_next(void *ctx,
struct fst_get_peer_ctx **get_ctx,
Boolean mb_only)
{
return fst_hostapd_get_sta(get_ctx, mb_only);
}
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
struct fst_wpa_obj *iface_obj)
{
iface_obj->ctx = hapd;
iface_obj->get_bssid = fst_hostapd_get_bssid_cb;
iface_obj->get_channel_info = fst_hostapd_get_channel_info_cb;
iface_obj->set_ies = fst_hostapd_set_ies_cb;
iface_obj->send_action = fst_hostapd_send_action_cb;
iface_obj->get_mb_ie = fst_hostapd_get_mb_ie_cb;
iface_obj->update_mb_ie = fst_hostapd_update_mb_ie_cb;
iface_obj->get_peer_first = fst_hostapd_get_peer_first;
iface_obj->get_peer_next = fst_hostapd_get_peer_next;
}
#endif /* CONFIG_FST */
/**
* hostapd_setup_interface_complete - Complete interface setup
*
@ -1495,6 +1641,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
hostapd_tx_queue_params(iface);
ap_list_init(iface);
dl_list_init(&iface->sta_seen);
hostapd_set_acl(hapd);
@ -1528,6 +1675,22 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
#ifdef NEED_AP_MLME
dfs_offload:
#endif /* NEED_AP_MLME */
#ifdef CONFIG_FST
if (hapd->iconf->fst_cfg.group_id[0]) {
struct fst_wpa_obj iface_obj;
fst_hostapd_fill_iface_obj(hapd, &iface_obj);
iface->fst = fst_attach(hapd->conf->iface, hapd->own_addr,
&iface_obj, &hapd->iconf->fst_cfg);
if (!iface->fst) {
wpa_printf(MSG_ERROR, "Could not attach to FST %s",
hapd->iconf->fst_cfg.group_id);
goto fail;
}
}
#endif /* CONFIG_FST */
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
@ -1544,6 +1707,12 @@ fail:
wpa_printf(MSG_ERROR, "Interface initialization failed");
hostapd_set_state(iface, HAPD_IFACE_DISABLED);
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
#ifdef CONFIG_FST
if (iface->fst) {
fst_detach(iface->fst);
iface->fst = NULL;
}
#endif /* CONFIG_FST */
if (iface->interfaces && iface->interfaces->terminate_on_error)
eloop_terminate();
return -1;
@ -1643,6 +1812,13 @@ void hostapd_interface_deinit(struct hostapd_iface *iface)
eloop_cancel_timeout(channel_list_update_timeout, iface, NULL);
iface->wait_channel_update = 0;
#ifdef CONFIG_FST
if (iface->fst) {
fst_detach(iface->fst);
iface->fst = NULL;
}
#endif /* CONFIG_FST */
for (j = iface->num_bss - 1; j >= 0; j--)
hostapd_bss_deinit(iface->bss[j]);
}
@ -2029,7 +2205,7 @@ hostapd_iface_alloc(struct hapd_interfaces *interfaces)
static struct hostapd_config *
hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
const char *ctrl_iface)
const char *ctrl_iface, const char *driver)
{
struct hostapd_bss_config *bss;
struct hostapd_config *conf;
@ -2042,6 +2218,21 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
return NULL;
}
if (driver) {
int j;
for (j = 0; wpa_drivers[j]; j++) {
if (os_strcmp(driver, wpa_drivers[j]->name) == 0) {
conf->driver = wpa_drivers[j];
goto skip;
}
}
wpa_printf(MSG_ERROR,
"Invalid/unknown driver '%s' - registering the default driver",
driver);
}
conf->driver = wpa_drivers[0];
if (conf->driver == NULL) {
wpa_printf(MSG_ERROR, "No driver wrappers registered!");
@ -2049,6 +2240,7 @@ hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
return NULL;
}
skip:
bss = conf->last_bss = conf->bss[0];
os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
@ -2209,8 +2401,14 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
if (conf && conf->bss)
os_strlcpy(conf->bss[0]->iface, buf,
sizeof(conf->bss[0]->iface));
} else
conf = hostapd_config_alloc(interfaces, buf, ptr);
} else {
char *driver = os_strchr(ptr, ' ');
if (driver)
*driver++ = '\0';
conf = hostapd_config_alloc(interfaces, buf, ptr, driver);
}
if (conf == NULL || conf->bss == NULL) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for configuration", __func__);
@ -2722,4 +2920,43 @@ hostapd_switch_channel_fallback(struct hostapd_iface *iface,
hostapd_enable_iface(iface);
}
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname)
{
size_t i, j;
for (i = 0; i < interfaces->count; i++) {
struct hostapd_iface *iface = interfaces->iface[i];
for (j = 0; j < iface->num_bss; j++) {
struct hostapd_data *hapd = iface->bss[j];
if (os_strcmp(ifname, hapd->conf->iface) == 0)
return hapd;
}
}
return NULL;
}
#endif /* NEED_AP_MLME */
void hostapd_periodic_iface(struct hostapd_iface *iface)
{
size_t i;
ap_list_timer(iface);
for (i = 0; i < iface->num_bss; i++) {
struct hostapd_data *hapd = iface->bss[i];
if (!hapd->started)
continue;
#ifndef CONFIG_NO_RADIUS
hostapd_acl_expire(hapd);
#endif /* CONFIG_NO_RADIUS */
}
}

View File

@ -41,6 +41,7 @@ struct hapd_interfaces {
size_t count;
int global_ctrl_sock;
struct wpa_ctrl_dst *global_ctrl_dst;
char *global_iface_path;
char *global_iface_name;
#ifndef CONFIG_NATIVE_WINDOWS
@ -49,6 +50,9 @@ struct hapd_interfaces {
struct hostapd_iface **iface;
size_t terminate_on_error;
#ifndef CONFIG_NO_VLAN
struct dynamic_iface *vlan_priv;
#endif /* CONFIG_NO_VLAN */
};
enum hostapd_chan_status {
@ -265,6 +269,7 @@ struct hostapd_data {
/** Key used for generating SAE anti-clogging tokens */
u8 sae_token_key[8];
struct os_reltime last_sae_token_key_update;
int dot11RSNASAERetransPeriod; /* msec */
#endif /* CONFIG_SAE */
#ifdef CONFIG_TESTING_OPTIONS
@ -276,6 +281,12 @@ struct hostapd_data {
};
struct hostapd_sta_info {
struct dl_list list;
u8 addr[ETH_ALEN];
struct os_reltime last_seen;
};
/**
* struct hostapd_iface - hostapd per-interface data structure
*/
@ -305,6 +316,10 @@ struct hostapd_iface {
unsigned int wait_channel_update:1;
unsigned int cac_started:1;
#ifdef CONFIG_FST
struct fst_iface *fst;
const struct wpabuf *fst_ies;
#endif /* CONFIG_FST */
/*
* When set, indicates that the driver will handle the AP
@ -400,6 +415,9 @@ struct hostapd_iface {
void (*scan_cb)(struct hostapd_iface *iface);
int num_ht40_scan_tries;
struct dl_list sta_seen; /* struct hostapd_sta_info */
unsigned int num_sta_seen;
};
/* hostapd.c */
@ -437,6 +455,7 @@ void
hostapd_switch_channel_fallback(struct hostapd_iface *iface,
const struct hostapd_freq_params *freq_params);
void hostapd_cleanup_cs_params(struct hostapd_data *hapd);
void hostapd_periodic_iface(struct hostapd_iface *iface);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
@ -464,4 +483,12 @@ const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
size_t identity_len, int phase2);
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname);
#ifdef CONFIG_FST
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
struct fst_wpa_obj *iface_obj);
#endif /* CONFIG_FST */
#endif /* HOSTAPD_H */

View File

@ -260,8 +260,14 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
if (res == 2)
ieee80211n_switch_pri_sec(iface);
if (res == 2) {
if (iface->conf->no_pri_sec_switch) {
wpa_printf(MSG_DEBUG,
"Cannot switch PRI/SEC channels due to local constraint");
} else {
ieee80211n_switch_pri_sec(iface);
}
}
return !!res;
}
@ -347,8 +353,13 @@ static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
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;
/*
* Note: Need to find the PRI channel also in cases where the affected
* channel is the SEC channel of a 40 MHz BSS, so need to include the
* scanning coverage here to be 40 MHz from the center frequency.
*/
affected_start = (pri_freq + sec_freq) / 2 - 40;
affected_end = (pri_freq + sec_freq) / 2 + 40;
wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
affected_start, affected_end);
@ -510,7 +521,11 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 0;
}
if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
/*
* Driver ACS chosen channel may not be HT40 due to internal driver
* restrictions.
*/
if (!iface->conf->acs && (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*]");
@ -717,6 +732,15 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
int ret;
if (!iface->conf->ieee80211n)
return 0;
if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211B &&
iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G &&
(iface->conf->ht_capab & HT_CAP_INFO_DSSS_CCK40MHZ)) {
wpa_printf(MSG_DEBUG,
"Disable HT capability [DSSS_CCK-40] on 5 GHz band");
iface->conf->ht_capab &= ~HT_CAP_INFO_DSSS_CCK40MHZ;
}
if (!ieee80211n_supported_ht_capab(iface))
return -1;
#ifdef CONFIG_IEEE80211AC
@ -740,6 +764,9 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int i;
struct hostapd_channel_data *chan;
if (!iface->current_mode)
return 0;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->chan != channel)
@ -801,6 +828,12 @@ hostapd_check_chans(struct hostapd_iface *iface)
static void hostapd_notify_bad_chans(struct hostapd_iface *iface)
{
if (!iface->current_mode) {
hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Hardware does not support configured mode");
return;
}
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
@ -891,14 +924,18 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
}
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) (hw_mode in hostapd.conf)",
(int) iface->conf->hw_mode);
return -2;
if (!(iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) ||
!(iface->drv_flags & WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY))
{
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) (hw_mode in hostapd.conf)",
(int) iface->conf->hw_mode);
return -2;
}
}
switch (hostapd_check_chans(iface)) {

View File

@ -36,6 +36,11 @@ static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
return -1;
}
static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
{
return -1;
}
static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
return -100;

View File

@ -23,6 +23,7 @@
#include "radius/radius_client.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
#include "fst/fst.h"
#include "hostapd.h"
#include "beacon.h"
#include "ieee802_11_auth.h"
@ -38,6 +39,7 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "wnm_ap.h"
#include "hw_features.h"
#include "ieee802_11.h"
#include "dfs.h"
@ -132,8 +134,7 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
}
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe)
u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
int privacy;
@ -166,20 +167,6 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
privacy = 1;
#endif /* CONFIG_HS20 */
if (sta) {
int policy, def_klen;
if (probe && sta->ssid_probe) {
policy = sta->ssid_probe->security_policy;
def_klen = sta->ssid_probe->wep.default_len;
} else {
policy = sta->ssid->security_policy;
def_klen = sta->ssid->wep.default_len;
}
privacy = policy != SECURITY_PLAINTEXT;
if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
privacy = 0;
}
if (privacy)
capab |= WLAN_CAPABILITY_PRIVACY;
@ -206,6 +193,7 @@ u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
}
#ifndef CONFIG_NO_RC4
static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
u16 auth_transaction, const u8 *challenge,
int iswep)
@ -259,6 +247,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
return 0;
}
#endif /* CONFIG_NO_RC4 */
static void send_auth_reply(struct hostapd_data *hapd,
@ -328,7 +317,6 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
#ifdef CONFIG_SAE
#define dot11RSNASAERetransPeriod 40 /* msec */
#define dot11RSNASAESync 5 /* attempts */
@ -511,12 +499,14 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
switch (sta->sae->state) {
case SAE_COMMITTED:
ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
break;
case SAE_CONFIRMED:
ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
break;
default:
@ -542,7 +532,7 @@ static void sae_set_retransmit_timer(struct hostapd_data *hapd,
return;
eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
eloop_register_timeout(0, hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
}
@ -624,7 +614,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
ret = auth_sae_send_commit(hapd, sta, bssid, 0);
if (ret)
return ret;
@ -784,6 +774,12 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
&token_len, hapd->conf->sae_groups);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
MAC2STR(sta->addr));
return;
}
if (token && check_sae_token(hapd, sta->addr, token, token_len)
< 0) {
wpa_printf(MSG_DEBUG, "SAE: Drop commit message with "
@ -934,6 +930,16 @@ static void handle_auth(struct hostapd_data *hapd,
challenge ? " challenge" : "",
seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
#ifdef CONFIG_NO_RC4
if (auth_alg == WLAN_AUTH_SHARED_KEY) {
wpa_printf(MSG_INFO,
"Unsupported authentication algorithm (%d)",
auth_alg);
resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
goto fail;
}
#endif /* CONFIG_NO_RC4 */
if (hapd->tkip_countermeasures) {
resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
goto fail;
@ -972,6 +978,61 @@ static void handle_auth(struct hostapd_data *hapd,
goto fail;
}
if (hapd->conf->no_auth_if_seen_on) {
struct hostapd_data *other;
other = sta_track_seen_on(hapd->iface, mgmt->sa,
hapd->conf->no_auth_if_seen_on);
if (other) {
u8 *pos;
u32 info;
u8 op_class, channel, phytype;
wpa_printf(MSG_DEBUG, "%s: Reject authentication from "
MACSTR " since STA has been seen on %s",
hapd->conf->iface, MAC2STR(mgmt->sa),
hapd->conf->no_auth_if_seen_on);
resp = WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION;
pos = &resp_ies[0];
*pos++ = WLAN_EID_NEIGHBOR_REPORT;
*pos++ = 13;
os_memcpy(pos, other->own_addr, ETH_ALEN);
pos += ETH_ALEN;
info = 0; /* TODO: BSSID Information */
WPA_PUT_LE32(pos, info);
pos += 4;
if (other->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
phytype = 8; /* dmg */
else if (other->iconf->ieee80211ac)
phytype = 9; /* vht */
else if (other->iconf->ieee80211n)
phytype = 7; /* ht */
else if (other->iconf->hw_mode ==
HOSTAPD_MODE_IEEE80211A)
phytype = 4; /* ofdm */
else if (other->iconf->hw_mode ==
HOSTAPD_MODE_IEEE80211G)
phytype = 6; /* erp */
else
phytype = 5; /* hrdsss */
if (ieee80211_freq_to_channel_ext(
hostapd_hw_get_freq(other,
other->iconf->channel),
other->iconf->secondary_channel,
other->iconf->ieee80211ac,
&op_class, &channel) == NUM_HOSTAPD_MODES) {
op_class = 0;
channel = other->iconf->channel;
}
*pos++ = op_class;
*pos++ = channel;
*pos++ = phytype;
resp_ies_len = pos - &resp_ies[0];
goto fail;
}
}
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
@ -1081,6 +1142,7 @@ static void handle_auth(struct hostapd_data *hapd,
sta->auth_alg = WLAN_AUTH_OPEN;
mlme_authenticate_indication(hapd, sta);
break;
#ifndef CONFIG_NO_RC4
case WLAN_AUTH_SHARED_KEY:
resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
fc & WLAN_FC_ISWEP);
@ -1094,6 +1156,7 @@ static void handle_auth(struct hostapd_data *hapd,
resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
}
break;
#endif /* CONFIG_NO_RC4 */
#ifdef CONFIG_IEEE80211R
case WLAN_AUTH_FT:
sta->auth_alg = WLAN_AUTH_FT;
@ -1297,8 +1360,7 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
return resp;
#ifdef CONFIG_IEEE80211N
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
elems.ht_capabilities_len);
resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
@ -1311,14 +1373,15 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
elems.vht_capabilities_len);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (hapd->iconf->ieee80211ac) {
resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
resp = set_sta_vht_opmode(hapd, sta, elems.vht_opmode_notif);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
}
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
!(sta->flags & WLAN_STA_VHT)) {
@ -1546,6 +1609,14 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
sta->hs20_ie = NULL;
#endif /* CONFIG_HS20 */
#ifdef CONFIG_FST
wpabuf_free(sta->mb_ies);
if (hapd->iface->fst)
sta->mb_ies = mb_ies_by_info(&elems.mb_ies);
else
sta->mb_ies = NULL;
#endif /* CONFIG_FST */
return WLAN_STATUS_SUCCESS;
}
@ -1594,7 +1665,7 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
send_len = IEEE80211_HDRLEN;
send_len += sizeof(reply->u.assoc_resp);
reply->u.assoc_resp.capab_info =
host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
host_to_le16(hostapd_own_capab_info(hapd));
reply->u.assoc_resp.status_code = host_to_le16(status_code);
reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
/* Supported rates */
@ -1634,6 +1705,14 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
if (sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
#ifdef CONFIG_FST
if (hapd->iface->fst_ies) {
os_memcpy(p, wpabuf_head(hapd->iface->fst_ies),
wpabuf_len(hapd->iface->fst_ies));
p += wpabuf_len(hapd->iface->fst_ies);
}
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
p = hostapd_eid_vendor_vht(hapd, p);
@ -2112,10 +2191,20 @@ static int handle_action(struct hostapd_data *hapd,
ieee802_11_rx_wnm_action_ap(hapd, mgmt, len);
return 1;
#endif /* CONFIG_WNM */
#ifdef CONFIG_FST
case WLAN_ACTION_FST:
if (hapd->iface->fst)
fst_rx_action(hapd->iface->fst, mgmt, len);
else
wpa_printf(MSG_DEBUG,
"FST: Ignore FST Action frame - no FST attached");
return 1;
#endif /* CONFIG_FST */
case WLAN_ACTION_PUBLIC:
case WLAN_ACTION_PROTECTED_DUAL:
#ifdef CONFIG_IEEE80211N
if (mgmt->u.action.u.public_action.action ==
if (len >= IEEE80211_HDRLEN + 2 &&
mgmt->u.action.u.public_action.action ==
WLAN_PA_20_40_BSS_COEX) {
wpa_printf(MSG_DEBUG,
"HT20/40 coex mgmt frame received from STA "
@ -2248,6 +2337,9 @@ int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
return 0;
}
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa);
switch (stype) {
case WLAN_FC_STYPE_AUTH:
wpa_printf(MSG_DEBUG, "mgmt::auth");
@ -2335,7 +2427,7 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
char *ifname_wds)
{
int i;
struct hostapd_ssid *ssid = sta->ssid;
struct hostapd_ssid *ssid = &hapd->conf->ssid;
if (hapd->conf->ieee802_1x || hapd->conf->wpa)
return;
@ -2473,11 +2565,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
* so bind it to the selected VLAN interface now, since the
* interface selection is not going to change anymore.
*/
if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
if (ap_sta_bind_vlan(hapd, sta) < 0)
return;
} else if (sta->vlan_id) {
/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
if (ap_sta_bind_vlan(hapd, sta) < 0)
return;
}

View File

@ -14,6 +14,7 @@ struct hostapd_data;
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@ -40,8 +41,7 @@ static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
return 0;
}
#endif /* NEED_AP_MLME */
u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
int probe);
u16 hostapd_own_capab_info(struct hostapd_data *hapd);
void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
@ -62,7 +62,7 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
const u8 *ht_capab);
u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ie, size_t len);
@ -70,7 +70,7 @@ void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len);
const u8 *vht_capab);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,

View File

@ -399,19 +399,15 @@ static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
/**
* hostapd_acl_expire - ACL cache expiration callback
* @eloop_ctx: struct hostapd_data *
* @timeout_ctx: Not used
* @hapd: struct hostapd_data *
*/
static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
void hostapd_acl_expire(struct hostapd_data *hapd)
{
struct hostapd_data *hapd = eloop_ctx;
struct os_reltime now;
os_get_reltime(&now);
hostapd_acl_expire_cache(hapd, &now);
hostapd_acl_expire_queries(hapd, &now);
eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
}
@ -561,6 +557,19 @@ hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->psk)
cache->accepted = HOSTAPD_ACL_REJECT;
if (cache->vlan_id &&
!hostapd_vlan_id_valid(hapd->conf->vlan, cache->vlan_id)) {
hostapd_logger(hapd, query->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN ID %d received from RADIUS server",
cache->vlan_id);
cache->vlan_id = 0;
}
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
!cache->vlan_id)
cache->accepted = HOSTAPD_ACL_REJECT;
} else
cache->accepted = HOSTAPD_ACL_REJECT;
cache->next = hapd->acl_cache;
@ -602,8 +611,6 @@ int hostapd_acl_init(struct hostapd_data *hapd)
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;
@ -619,8 +626,6 @@ 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 */

View File

@ -24,5 +24,6 @@ int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
void hostapd_acl_expire(struct hostapd_data *hapd);
#endif /* IEEE802_11_AUTH_H */

View File

@ -209,7 +209,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
struct hostapd_iface *iface = hapd->iface;
struct ieee80211_2040_bss_coex_ie *bc_ie;
struct ieee80211_2040_intol_chan_report *ic_report;
int is_ht_allowed = 1;
int is_ht40_allowed = 1;
int i;
const u8 *start = (const u8 *) mgmt;
const u8 *data = start + IEEE80211_HDRLEN + 2;
@ -242,7 +242,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"20 MHz BSS width request bit is set in BSS coexistence information field");
is_ht_allowed = 0;
is_ht40_allowed = 0;
}
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
@ -250,7 +250,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"40 MHz intolerant bit is set in BSS coexistence information field");
is_ht_allowed = 0;
is_ht40_allowed = 0;
}
if (start + len - data >= 3 &&
@ -276,13 +276,13 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
HOSTAPD_LEVEL_DEBUG,
"20_40_INTOLERANT channel %d reported",
chan);
is_ht_allowed = 0;
is_ht40_allowed = 0;
}
}
wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
is_ht_allowed, iface->num_sta_ht40_intolerant);
wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
is_ht40_allowed, iface->num_sta_ht40_intolerant);
if (!is_ht_allowed &&
if (!is_ht40_allowed &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
if (iface->conf->secondary_channel) {
hostapd_logger(hapd, mgmt->sa,
@ -310,12 +310,15 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd,
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len)
const u8 *ht_capab)
{
/* Disable HT caps for STAs associated to no-HT BSSes. */
/*
* Disable HT caps for STAs associated to no-HT BSSes, or for stations
* that did not specify a valid WMM IE in the (Re)Association Request
* frame.
*/
if (!ht_capab ||
ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
hapd->conf->disable_11n) {
!(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;

View File

@ -132,11 +132,10 @@ static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_capab, size_t vht_capab_len)
const u8 *vht_capab)
{
/* Disable VHT caps for STAs associated to no-VHT BSSes. */
if (!vht_capab ||
vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
hapd->conf->disable_11ac ||
!check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;

View File

@ -125,6 +125,9 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
struct sta_info *sta,
int idx, int broadcast,
@ -204,7 +207,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
}
void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
{
struct eapol_authenticator *eapol = hapd->eapol_auth;
struct eapol_state_machine *sm = sta->eapol_sm;
@ -259,6 +262,9 @@ void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
}
}
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
const char *radius_mode_txt(struct hostapd_data *hapd)
{
@ -346,7 +352,8 @@ static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd,
return -1;
}
suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ?
suite = wpa_cipher_to_suite(((hapd->conf->wpa & 0x2) ||
hapd->conf->osen) ?
WPA_PROTO_RSN : WPA_PROTO_WPA,
hapd->conf->wpa_group);
if (!hostapd_config_get_radius_attr(req_attr,
@ -453,7 +460,7 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211R */
if (hapd->conf->wpa && sta->wpa_sm &&
if ((hapd->conf->wpa || hapd->conf->osen) && sta->wpa_sm &&
add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0)
return -1;
@ -599,7 +606,7 @@ static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
goto fail;
}
if (eap && !radius_msg_add_eap(msg, eap, len)) {
if (!radius_msg_add_eap(msg, eap, len)) {
wpa_printf(MSG_INFO, "Could not add EAP-Message");
goto fail;
}
@ -1108,8 +1115,6 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
if (pmksa) {
int old_vlanid;
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
"PMK from PMKSA cache - skip IEEE 802.1X/EAP");
@ -1123,11 +1128,8 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
sta->eapol_sm->authFail = FALSE;
if (sta->eapol_sm->eap)
eap_sm_notify_cached(sta->eapol_sm->eap);
old_vlanid = sta->vlan_id;
pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
ap_sta_bind_vlan(hapd, sta, old_vlanid);
ap_sta_bind_vlan(hapd, sta);
} else {
if (reassoc) {
/*
@ -1290,7 +1292,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
struct sta_info *sta,
struct radius_msg *msg)
{
u8 *class;
u8 *attr_class;
size_t class_len;
struct eapol_state_machine *sm = sta->eapol_sm;
int count, i;
@ -1312,12 +1314,12 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
nclass_count = 0;
class = NULL;
attr_class = NULL;
for (i = 0; i < count; i++) {
do {
if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
&class, &class_len,
class) < 0) {
&attr_class, &class_len,
attr_class) < 0) {
i = count;
break;
}
@ -1327,7 +1329,7 @@ static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
if (nclass[nclass_count].data == NULL)
break;
os_memcpy(nclass[nclass_count].data, class, class_len);
os_memcpy(nclass[nclass_count].data, attr_class, class_len);
nclass[nclass_count].len = class_len;
nclass_count++;
}
@ -1590,7 +1592,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct hostapd_data *hapd = data;
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
int session_timeout_set, old_vlanid = 0;
int session_timeout_set, vlan_id = 0;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@ -1657,20 +1659,27 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
vlan_id = 0;
#ifndef CONFIG_NO_VLAN
else {
old_vlanid = sta->vlan_id;
sta->vlan_id = radius_msg_get_vlanid(msg);
}
if (sta->vlan_id > 0 &&
hostapd_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
else
vlan_id = radius_msg_get_vlanid(msg);
if (vlan_id > 0 &&
hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"VLAN ID %d", sta->vlan_id);
} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
"VLAN ID %d", vlan_id);
} else if (vlan_id > 0) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Invalid VLAN ID %d received from RADIUS server",
vlan_id);
break;
} else if (hapd->conf->ssid.dynamic_vlan ==
DYNAMIC_VLAN_REQUIRED) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
@ -1681,7 +1690,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
}
#endif /* CONFIG_NO_VLAN */
if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
sta->vlan_id = vlan_id;
if ((sta->flags & WLAN_STA_ASSOC) &&
ap_sta_bind_vlan(hapd, sta) < 0)
break;
sta->session_timeout_set = !!session_timeout_set;
@ -1926,10 +1937,11 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
struct hostapd_data *hapd = ctx;
const struct hostapd_eap_user *eap_user;
int i;
int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
return -1;
goto out;
os_memset(user, 0, sizeof(*user));
user->phase2 = phase2;
@ -1941,7 +1953,7 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
return -1;
goto out;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
@ -1951,8 +1963,13 @@ static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
rv = 0;
return 0;
out:
if (rv)
wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
return rv;
}
@ -2012,9 +2029,13 @@ static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
{
#ifndef CONFIG_FIPS
#ifndef CONFIG_NO_RC4
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
ieee802_1x_tx_key(hapd, sta);
#endif /* CONFIG_NO_RC4 */
#endif /* CONFIG_FIPS */
}
@ -2085,6 +2106,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
conf.erp_domain = hapd->conf->erp_domain;
conf.erp = hapd->conf->eap_server_erp;
conf.tls_session_lifetime = hapd->conf->tls_session_lifetime;
conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
@ -2332,9 +2354,9 @@ void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
}
static const char * bool_txt(Boolean bool)
static const char * bool_txt(Boolean val)
{
return bool ? "TRUE" : "FALSE";
return val ? "TRUE" : "FALSE";
}

View File

@ -23,7 +23,6 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
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);

View File

@ -81,12 +81,24 @@ static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
}
static void ucast_to_stas(struct hostapd_data *hapd, const u8 *buf, size_t len)
{
struct sta_info *sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!(sta->flags & WLAN_STA_AUTHORIZED))
continue;
x_snoop_mcast_to_ucast_convert_send(hapd, sta, (u8 *) buf, len);
}
}
static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
struct hostapd_data *hapd = ctx;
struct icmpv6_ndmsg *msg;
struct in6_addr *saddr;
struct in6_addr saddr;
struct sta_info *sta;
int res;
char addrtxt[INET6_ADDRSTRLEN + 1];
@ -101,25 +113,30 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
if (msg->opt_type != SOURCE_LL_ADDR)
return;
saddr = &msg->ipv6h.ip6_src;
if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
/*
* IPv6 header may not be 32-bit aligned in the buffer, so use
* a local copy to avoid unaligned reads.
*/
os_memcpy(&saddr, &msg->ipv6h.ip6_src, sizeof(saddr));
if (!(saddr.s6_addr32[0] == 0 && saddr.s6_addr32[1] == 0 &&
saddr.s6_addr32[2] == 0 && saddr.s6_addr32[3] == 0)) {
if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
return;
sta = ap_get_sta(hapd, msg->opt_lladdr);
if (!sta)
return;
if (sta_has_ip6addr(sta, saddr))
if (sta_has_ip6addr(sta, &saddr))
return;
if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
== NULL)
if (inet_ntop(AF_INET6, &saddr, addrtxt,
sizeof(addrtxt)) == NULL)
addrtxt[0] = '\0';
wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
MACSTR, addrtxt, MAC2STR(sta->addr));
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &saddr);
res = hostapd_drv_br_add_ip_neigh(hapd, 6,
(u8 *) &saddr,
128, sta->addr);
if (res) {
wpa_printf(MSG_ERROR,
@ -128,21 +145,17 @@ static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
return;
}
if (sta_ip6addr_add(sta, saddr))
if (sta_ip6addr_add(sta, &saddr))
return;
}
break;
case ROUTER_ADVERTISEMENT:
if (!hapd->conf->disable_dgaf)
return;
/* fall through */
if (hapd->conf->disable_dgaf)
ucast_to_stas(hapd, buf, len);
break;
case NEIGHBOR_ADVERTISEMENT:
for (sta = hapd->sta_list; sta; sta = sta->next) {
if (!(sta->flags & WLAN_STA_AUTHORIZED))
continue;
x_snoop_mcast_to_ucast_convert_send(hapd, sta,
(u8 *) buf, len);
}
if (hapd->conf->na_mcast_to_ucast)
ucast_to_stas(hapd, buf, len);
break;
default:
break;

View File

@ -16,6 +16,7 @@
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
#include "fst/fst.h"
#include "hostapd.h"
#include "accounting.h"
#include "ieee802_1x.h"
@ -171,6 +172,19 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
#ifndef CONFIG_NO_VLAN
if (sta->vlan_id_bound) {
/*
* Need to remove the STA entry before potentially removing the
* VLAN.
*/
if (hapd->iface->driver_ap_teardown &&
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
vlan_remove_dynamic(hapd, sta->vlan_id_bound);
}
#endif /* CONFIG_NO_VLAN */
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
@ -283,6 +297,9 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->wps_ie);
wpabuf_free(sta->p2p_ie);
wpabuf_free(sta->hs20_ie);
#ifdef CONFIG_FST
wpabuf_free(sta->mb_ies);
#endif /* CONFIG_FST */
os_free(sta->ht_capabilities);
os_free(sta->vht_capabilities);
@ -619,7 +636,6 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
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);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
dl_list_init(&sta->ip6addr);
@ -768,26 +784,19 @@ int ap_sta_wps_cancel(struct hostapd_data *hapd,
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid)
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#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;
int old_vlanid = sta->vlan_id_bound;
iface = hapd->conf->iface;
if (sta->ssid->vlan[0])
iface = sta->ssid->vlan;
if (hapd->conf->ssid.vlan[0])
iface = hapd->conf->ssid.vlan;
if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
struct hostapd_vlan *wildcard_vlan = NULL;
@ -805,6 +814,14 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
iface = vlan->ifname;
}
/*
* Do not increment ref counters if the VLAN ID remains same, but do
* not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
* have been called before.
*/
if (sta->vlan_id == old_vlanid)
goto skip_counting;
if (sta->vlan_id > 0 && vlan == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
@ -825,7 +842,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
}
iface = vlan->ifname;
if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
@ -838,7 +855,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
"interface '%s'", iface);
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
if (sta->vlan_id > 0) {
if (vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@ -852,7 +869,7 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
* 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) {
if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
@ -862,6 +879,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
}
}
/* ref counters have been increased, so mark the station */
sta->vlan_id_bound = sta->vlan_id;
skip_counting:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
@ -876,10 +897,10 @@ int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
"entry to vlan_id=%d", sta->vlan_id);
}
done:
/* During 1x reauth, if the vlan id changes, then remove the old id. */
if (old_vlanid > 0)
if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
vlan_remove_dynamic(hapd, old_vlanid);
done:
return ret;
#else /* CONFIG_NO_VLAN */
@ -1043,6 +1064,16 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
AP_STA_DISCONNECTED "%s", buf);
}
#ifdef CONFIG_FST
if (hapd->iface->fst) {
if (authorized)
fst_notify_peer_connected(hapd->iface->fst, sta->addr);
else
fst_notify_peer_disconnected(hapd->iface->fst,
sta->addr);
}
#endif /* CONFIG_FST */
}

View File

@ -117,10 +117,8 @@ struct sta_info {
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;
int vlan_id; /* 0: none, >0: VID */
int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@ -155,6 +153,9 @@ struct sta_info {
struct wpabuf *hs20_deauth_req;
char *hs20_session_info_url;
int hs20_disassoc_timer;
#ifdef CONFIG_FST
struct wpabuf *mb_ies; /* MB IEs from (Re)Association Request */
#endif /* CONFIG_FST */
struct os_reltime connected_time;
@ -218,8 +219,7 @@ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
int ap_sta_wps_cancel(struct hostapd_data *hapd,
struct sta_info *sta, void *ctx);
#endif /* CONFIG_WPS */
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
int old_vlanid);
int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
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);

View File

@ -10,6 +10,7 @@
#include "common.h"
#include "common/ieee802_11_defs.h"
#include "fst/fst.h"
#include "sta_info.h"
#include "hostapd.h"
@ -55,10 +56,20 @@ static int prune_associations(struct hostapd_iface *iface, void *ctx)
ohapd = iface->bss[j];
if (ohapd == data->hapd)
continue;
#ifdef CONFIG_FST
/* Don't prune STAs belong to same FST */
if (ohapd->iface->fst &&
data->hapd->iface->fst &&
fst_are_ifaces_aggregated(ohapd->iface->fst,
data->hapd->iface->fst))
continue;
#endif /* CONFIG_FST */
osta = ap_get_sta(ohapd, data->addr);
if (!osta)
continue;
wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR,
ohapd->conf->iface, MAC2STR(osta->addr));
ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
}

View File

@ -9,6 +9,13 @@
*/
#include "utils/includes.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>
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
#include "utils/common.h"
#include "hostapd.h"
@ -20,12 +27,6 @@
#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"
@ -34,6 +35,90 @@ struct full_dynamic_vlan {
int s; /* socket on which to listen for new/removed interfaces. */
};
#define DVLAN_CLEAN_BR 0x1
#define DVLAN_CLEAN_VLAN 0x2
#define DVLAN_CLEAN_VLAN_PORT 0x4
struct dynamic_iface {
char ifname[IFNAMSIZ + 1];
int usage;
int clean;
struct dynamic_iface *next;
};
/* Increment ref counter for ifname and add clean flag.
* If not in list, add it only if some flags are given.
*/
static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
int clean)
{
struct dynamic_iface *next, **dynamic_ifaces;
struct hapd_interfaces *interfaces;
interfaces = hapd->iface->interfaces;
dynamic_ifaces = &interfaces->vlan_priv;
for (next = *dynamic_ifaces; next; next = next->next) {
if (os_strcmp(ifname, next->ifname) == 0)
break;
}
if (next) {
next->usage++;
next->clean |= clean;
return;
}
if (!clean)
return;
next = os_zalloc(sizeof(*next));
if (!next)
return;
os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
next->usage = 1;
next->clean = clean;
next->next = *dynamic_ifaces;
*dynamic_ifaces = next;
}
/* Decrement reference counter for given ifname.
* Return clean flag iff reference counter was decreased to zero, else zero
*/
static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
{
struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
struct hapd_interfaces *interfaces;
int clean;
interfaces = hapd->iface->interfaces;
dynamic_ifaces = &interfaces->vlan_priv;
for (next = *dynamic_ifaces; next; next = next->next) {
if (os_strcmp(ifname, next->ifname) == 0)
break;
prev = next;
}
if (!next)
return 0;
next->usage--;
if (next->usage)
return 0;
if (prev)
prev->next = next->next;
else
*dynamic_ifaces = next->next;
clean = next->clean;
os_free(next);
return clean;
}
static int ifconfig_helper(const char *if_name, int up)
{
@ -481,11 +566,13 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
int clean;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
vlan->configured = 1;
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
@ -500,8 +587,8 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
"brvlan%d", vlan->vlan_id);
}
if (!br_addbr(br_name))
vlan->clean |= DVLAN_CLEAN_BR;
dyn_iface_get(hapd, br_name,
br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
ifconfig_up(br_name);
@ -517,13 +604,16 @@ static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
sizeof(vlan_ifname),
"vlan%d", vlan->vlan_id);
clean = 0;
ifconfig_up(tagged_interface);
if (!vlan_add(tagged_interface, vlan->vlan_id,
vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN;
clean |= DVLAN_CLEAN_VLAN;
if (!br_addif(br_name, vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
clean |= DVLAN_CLEAN_VLAN_PORT;
dyn_iface_get(hapd, vlan_ifname, clean);
ifconfig_up(vlan_ifname);
}
@ -547,13 +637,15 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
int clean;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
first = prev = vlan;
while (vlan) {
if (os_strcmp(ifname, vlan->ifname) == 0) {
if (os_strcmp(ifname, vlan->ifname) == 0 &&
vlan->configured) {
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
hapd->conf->vlan_bridge,
@ -581,20 +673,27 @@ static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
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)
clean = dyn_iface_put(hapd, vlan_ifname);
if (clean & DVLAN_CLEAN_VLAN_PORT)
br_delif(br_name, vlan_ifname);
if (clean & DVLAN_CLEAN_VLAN) {
ifconfig_down(vlan_ifname);
vlan_rem(vlan_ifname);
}
}
if ((vlan->clean & DVLAN_CLEAN_BR) &&
clean = dyn_iface_put(hapd, br_name);
if ((clean & DVLAN_CLEAN_BR) &&
br_getnumports(br_name) == 0) {
ifconfig_down(br_name);
br_delbr(br_name);
}
}
if (os_strcmp(ifname, vlan->ifname) == 0) {
if (vlan == first) {
hapd->conf->vlan = vlan->next;
} else {
@ -651,6 +750,11 @@ vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
if (!ifname[0])
return;
if (del && if_nametoindex(ifname)) {
/* interface still exists, race condition ->
* iface has just been recreated */
return;
}
wpa_printf(MSG_DEBUG,
"VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
@ -778,8 +882,7 @@ static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid, const char *dyn_vlan)
int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
{
int i;
@ -789,10 +892,11 @@ int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
/* 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] &&
if (hapd->conf->ssid.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]))
i == hapd->conf->ssid.wep.idx, NULL, 0,
hapd->conf->ssid.wep.key[i],
hapd->conf->ssid.wep.len[i]))
{
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
"encryption for dynamic VLAN");
@ -953,7 +1057,8 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
return 1;
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
__func__, hapd->conf->iface, vlan_id);
vlan = hapd->conf->vlan;
while (vlan) {
@ -967,8 +1072,12 @@ int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
if (vlan == NULL)
return 1;
if (vlan->dynamic_vlan == 0)
if (vlan->dynamic_vlan == 0) {
hostapd_vlan_if_remove(hapd, vlan->ifname);
#ifdef CONFIG_FULL_DYNAMIC_VLAN
vlan_dellink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
}
return 0;
}

View File

@ -18,7 +18,6 @@ struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
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)
@ -43,7 +42,6 @@ static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
}
static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
struct hostapd_ssid *mssid,
const char *dyn_vlan)
{
return -1;

View File

@ -31,7 +31,7 @@
*/
int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int ret = -1;
int err, ret = -1;
struct nl_sock *handle = NULL;
struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
@ -58,14 +58,18 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
goto vlan_add_error;
}
if (nl_connect(handle, NETLINK_ROUTE) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
err = nl_connect(handle, NETLINK_ROUTE);
if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
nl_geterror(err));
goto vlan_add_error;
}
if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
if (err < 0) {
cache = NULL;
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
nl_geterror(err));
goto vlan_add_error;
}
@ -92,23 +96,29 @@ int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
goto vlan_add_error;
}
if (rtnl_link_set_type(rlink, "vlan") < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
err = rtnl_link_set_type(rlink, "vlan");
if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to set link type: %s",
nl_geterror(err));
goto vlan_add_error;
}
rtnl_link_set_link(rlink, if_idx);
rtnl_link_set_name(rlink, vlan_if_name);
if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
err = rtnl_link_vlan_set_id(rlink, vid);
if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id: %s",
nl_geterror(err));
goto vlan_add_error;
}
if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
err = rtnl_link_add(handle, rlink, NLM_F_CREATE);
if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
"vlan %d on %s (%d)",
vlan_if_name, vid, if_name, if_idx);
"vlan %d on %s (%d): %s",
vlan_if_name, vid, if_name, if_idx,
nl_geterror(err));
goto vlan_add_error;
}
@ -127,7 +137,7 @@ vlan_add_error:
int vlan_rem(const char *if_name)
{
int ret = -1;
int err, ret = -1;
struct nl_sock *handle = NULL;
struct nl_cache *cache = NULL;
struct rtnl_link *rlink = NULL;
@ -140,14 +150,18 @@ int vlan_rem(const char *if_name)
goto vlan_rem_error;
}
if (nl_connect(handle, NETLINK_ROUTE) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
err = nl_connect(handle, NETLINK_ROUTE);
if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink: %s",
nl_geterror(err));
goto vlan_rem_error;
}
if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
err = rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache);
if (err < 0) {
cache = NULL;
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache: %s",
nl_geterror(err));
goto vlan_rem_error;
}
@ -158,9 +172,10 @@ int vlan_rem(const char *if_name)
goto vlan_rem_error;
}
if (rtnl_link_delete(handle, rlink) < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
if_name);
err = rtnl_link_delete(handle, rlink);
if (err < 0) {
wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s: %s",
if_name, nl_geterror(err));
goto vlan_rem_error;
}

View File

@ -274,6 +274,9 @@ void hostapd_wmm_action(struct hostapd_data *hapd,
return;
}
if (left < 0)
return; /* not a valid WMM Action frame */
/* extract the tspec info element */
if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,

View File

@ -45,6 +45,12 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, struct wpa_ptk *ptk);
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@ -67,6 +73,14 @@ static inline int wpa_auth_mic_failure_report(
}
static inline void wpa_auth_psk_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
if (wpa_auth->cb.psk_failure_report)
wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
}
static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var,
int value)
@ -254,15 +268,22 @@ static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_authenticator *wpa_auth = eloop_ctx;
struct wpa_group *group;
struct wpa_group *group, *next;
wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
for (group = wpa_auth->group; group; group = group->next) {
group = wpa_auth->group;
while (group) {
wpa_group_get(wpa_auth, group);
group->GTKReKey = TRUE;
do {
group->changed = FALSE;
wpa_group_sm_step(wpa_auth, group);
} while (group->changed);
next = group->next;
wpa_group_put(wpa_auth, group);
group = next;
}
if (wpa_auth->conf.wpa_group_rekey) {
@ -565,6 +586,7 @@ wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr,
sm->wpa_auth = wpa_auth;
sm->group = wpa_auth->group;
wpa_group_get(sm->wpa_auth, sm->group);
return sm;
}
@ -643,6 +665,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#endif /* CONFIG_IEEE80211R */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
wpa_group_put(sm->wpa_auth, sm->group);
os_free(sm);
}
@ -1517,6 +1540,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
else
WPA_PUT_BE16(key->key_data_length,
key_data_len);
#ifndef CONFIG_NO_RC4
} else if (sm->PTK.kek_len == 16) {
u8 ek[32];
os_memcpy(key->key_iv,
@ -1532,6 +1556,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
else
WPA_PUT_BE16(key->key_data_length,
key_data_len);
#endif /* CONFIG_NO_RC4 */
} else {
os_free(hdr);
os_free(buf);
@ -1646,7 +1671,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
}
int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
int wpa_auth_sm_event(struct wpa_state_machine *sm, enum wpa_event event)
{
int remove_ptk = 1;
@ -1734,6 +1759,14 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
wpa_remove_ptk(sm);
}
if (sm->in_step_loop) {
/*
* wpa_sm_step() is already running - avoid recursive call to
* it by making the existing loop process the new update.
*/
sm->changed = TRUE;
return 0;
}
return wpa_sm_step(sm);
}
@ -1818,9 +1851,13 @@ static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
group->reject_4way_hs_for_entropy = FALSE;
}
wpa_group_init_gmk_and_counter(wpa_auth, group);
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0 ||
wpa_gtk_update(wpa_auth, group) < 0 ||
wpa_group_config_group_keys(wpa_auth, group) < 0) {
wpa_printf(MSG_INFO, "WPA: GMK/GTK setup failed");
group->first_sta_seen = FALSE;
group->reject_4way_hs_for_entropy = TRUE;
}
}
@ -1985,7 +2022,7 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_ptk PTK;
int ok = 0;
int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
@ -2001,6 +2038,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
psk_found = 1;
} else
pmk = sm->PMK;
@ -2020,6 +2058,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
if (psk_found)
wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
return;
}
@ -2983,9 +3023,9 @@ void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
}
static const char * wpa_bool_txt(int bool)
static const char * wpa_bool_txt(int val)
{
return bool ? "TRUE" : "FALSE";
return val ? "TRUE" : "FALSE";
}
@ -3270,6 +3310,63 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
}
/*
* Remove and free the group from wpa_authenticator. This is triggered by a
* callback to make sure nobody is currently iterating the group list while it
* gets modified.
*/
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
struct wpa_group *prev = wpa_auth->group;
wpa_printf(MSG_DEBUG, "WPA: Remove group state machine for VLAN-ID %d",
group->vlan_id);
while (prev) {
if (prev->next == group) {
/* This never frees the special first group as needed */
prev->next = group->next;
os_free(group);
break;
}
prev = prev->next;
}
}
/* Increase the reference counter for group */
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
/* Skip the special first group */
if (wpa_auth->group == group)
return;
group->references++;
}
/* Decrease the reference counter and maybe free the group */
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
/* Skip the special first group */
if (wpa_auth->group == group)
return;
group->references--;
if (group->references)
return;
wpa_group_free(wpa_auth, group);
}
/*
* Add a group that has its references counter set to zero. Caller needs to
* call wpa_group_get() on the return value to mark the entry in use.
*/
static struct wpa_group *
wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
{
@ -3320,7 +3417,10 @@ int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
"machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
wpa_group_get(sm->wpa_auth, group);
wpa_group_put(sm->wpa_auth, sm->group);
sm->group = group;
return 0;
}

View File

@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
* Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -12,6 +12,9 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
#include "common/ieee802_11_defs.h"
#define MAX_OWN_IE_OVERRIDE 256
#ifdef _MSC_VER
#pragma pack(push, 1)
@ -146,8 +149,7 @@ struct wpa_auth_config {
int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
#define SSID_LEN 32
u8 ssid[SSID_LEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
@ -164,6 +166,8 @@ struct wpa_auth_config {
int ap_mlme;
#ifdef CONFIG_TESTING_OPTIONS
double corrupt_gtk_rekey_mic_probability;
u8 own_ie_override[MAX_OWN_IE_OVERRIDE];
size_t own_ie_override_len;
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
u8 ip_addr_go[4];
@ -189,6 +193,7 @@ struct wpa_auth_callbacks {
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
int (*mic_failure_report)(void *ctx, const u8 *addr);
void (*psk_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);
@ -251,12 +256,12 @@ 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 {
enum wpa_event {
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);
int wpa_auth_sm_event(struct wpa_state_machine *sm, enum 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);

View File

@ -534,10 +534,8 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
return pos;
}
#ifdef NEED_AP_MLME
if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
if (parse.wmm_tspec) {
struct wmm_tspec_element *tspec;
int res;
if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
@ -555,7 +553,13 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
}
tspec = (struct wmm_tspec_element *) pos;
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
res = wmm_process_tspec(tspec);
}
#ifdef NEED_AP_MLME
if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
int res;
res = wmm_process_tspec((struct wmm_tspec_element *) pos);
wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
rdie->status_code =
@ -566,20 +570,17 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
else {
/* TSPEC accepted; include updated TSPEC in response */
rdie->descr_count = 1;
pos += sizeof(*tspec);
pos += sizeof(struct wmm_tspec_element);
}
return pos;
}
#endif /* NEED_AP_MLME */
if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
struct wmm_tspec_element *tspec;
int res;
tspec = (struct wmm_tspec_element *) pos;
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
sizeof(*tspec));
sizeof(struct wmm_tspec_element));
if (res >= 0) {
if (res)
rdie->status_code = host_to_le16(res);
@ -587,7 +588,7 @@ static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
/* TSPEC accepted; include updated TSPEC in
* response */
rdie->descr_count = 1;
pos += sizeof(*tspec);
pos += sizeof(struct wmm_tspec_element);
}
return pos;
}

View File

@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
#include "common/wpa_ctrl.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
@ -53,8 +54,8 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len;
if (wconf->ssid_len > SSID_LEN)
wconf->ssid_len = SSID_LEN;
if (wconf->ssid_len > SSID_MAX_LEN)
wconf->ssid_len = SSID_MAX_LEN;
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN);
@ -91,6 +92,13 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
#ifdef CONFIG_TESTING_OPTIONS
wconf->corrupt_gtk_rekey_mic_probability =
iconf->corrupt_gtk_rekey_mic_probability;
if (conf->own_ie_override &&
wpabuf_len(conf->own_ie_override) <= MAX_OWN_IE_OVERRIDE) {
wconf->own_ie_override_len = wpabuf_len(conf->own_ie_override);
os_memcpy(wconf->own_ie_override,
wpabuf_head(conf->own_ie_override),
wconf->own_ie_override_len);
}
#endif /* CONFIG_TESTING_OPTIONS */
#ifdef CONFIG_P2P
os_memcpy(wconf->ip_addr_go, conf->ip_addr_go, 4);
@ -144,6 +152,14 @@ static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
}
static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
{
struct hostapd_data *hapd = ctx;
wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
MAC2STR(addr));
}
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
wpa_eapol_variable var, int value)
{
@ -579,6 +595,7 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
cb.logger = hostapd_wpa_auth_logger;
cb.disconnect = hostapd_wpa_auth_disconnect;
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
cb.psk_failure_report = hostapd_wpa_auth_psk_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;
@ -620,7 +637,8 @@ int hostapd_setup_wpa(struct hostapd_data *hapd)
}
#ifdef CONFIG_IEEE80211R
if (!hostapd_drv_none(hapd)) {
if (!hostapd_drv_none(hapd) && hapd->conf->ft_over_ds &&
wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) {
hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
hapd->conf->bridge :
hapd->conf->iface, NULL, ETH_P_RRB,

View File

@ -169,6 +169,8 @@ struct wpa_group {
u8 IGTK[2][WPA_IGTK_MAX_LEN];
int GN_igtk, GM_igtk;
#endif /* CONFIG_IEEE80211W */
/* Number of references except those in struct wpa_group->next */
unsigned int references;
};

View File

@ -261,7 +261,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
#ifdef CONFIG_IEEE80211W
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
if (pos + 2 + 4 > buf + len)
return -1;
if (pmkid == NULL) {
@ -377,6 +378,23 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
u8 *pos, buf[128];
int res;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_auth->conf.own_ie_override_len) {
wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
wpa_auth->conf.own_ie_override,
wpa_auth->conf.own_ie_override_len);
os_free(wpa_auth->wpa_ie);
wpa_auth->wpa_ie =
os_malloc(wpa_auth->conf.own_ie_override_len);
if (wpa_auth->wpa_ie == NULL)
return -1;
os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
wpa_auth->conf.own_ie_override_len);
wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
return 0;
}
#endif /* CONFIG_TESTING_OPTIONS */
pos = buf;
if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {

View File

@ -324,7 +324,7 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
bss->wps_state = 2;
if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
if (cred->ssid_len <= SSID_MAX_LEN) {
os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
bss->ssid.ssid_len = cred->ssid_len;
bss->ssid.ssid_set = 1;
@ -347,8 +347,12 @@ static int hapd_wps_reconfig_in_memory(struct hostapd_data *hapd,
bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
bss->wpa_pairwise = 0;
if (cred->encr_type & WPS_ENCR_AES)
bss->wpa_pairwise |= WPA_CIPHER_CCMP;
if (cred->encr_type & WPS_ENCR_AES) {
if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
bss->wpa_pairwise |= WPA_CIPHER_GCMP;
else
bss->wpa_pairwise |= WPA_CIPHER_CCMP;
}
if (cred->encr_type & WPS_ENCR_TKIP)
bss->wpa_pairwise |= WPA_CIPHER_TKIP;
bss->rsn_pairwise = bss->wpa_pairwise;
@ -448,6 +452,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
os_free(hapd->wps->network_key);
hapd->wps->network_key = NULL;
hapd->wps->network_key_len = 0;
} else if ((cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK)) &&
(cred->key_len < 8 || cred->key_len > 2 * PMK_LEN)) {
wpa_printf(MSG_INFO, "WPS: Invalid key length %lu for WPA/WPA2",
(unsigned long) cred->key_len);
return -1;
} else {
if (hapd->wps->network_key == NULL ||
hapd->wps->network_key_len < cred->key_len) {
@ -530,7 +539,11 @@ static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
fprintf(nconf, "wpa_pairwise=");
prefix = "";
if (cred->encr_type & WPS_ENCR_AES) {
fprintf(nconf, "CCMP");
if (hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD)
fprintf(nconf, "GCMP");
else
fprintf(nconf, "CCMP");
prefix = " ";
}
if (cred->encr_type & WPS_ENCR_TKIP) {
@ -844,7 +857,9 @@ static int hostapd_wps_rf_band_cb(void *ctx)
struct hostapd_data *hapd = ctx;
return hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
WPS_RF_50GHZ :
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
}
@ -856,8 +871,10 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
wpabuf_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = NULL;
if (deinit_only)
if (deinit_only) {
hostapd_reset_ap_wps_ie(hapd);
return;
}
hostapd_set_ap_wps_ie(hapd);
}
@ -1039,7 +1056,9 @@ int hostapd_init_wps(struct hostapd_data *hapd,
} else {
wps->dev.rf_bands =
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
WPS_RF_50GHZ :
hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211AD ?
WPS_RF_60GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
}
if (conf->wpa & WPA_PROTO_RSN) {
@ -1285,30 +1304,53 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
}
struct wps_button_pushed_ctx {
const u8 *p2p_dev_addr;
unsigned int count;
};
static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
{
const u8 *p2p_dev_addr = ctx;
if (hapd->wps == NULL)
return -1;
return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
struct wps_button_pushed_ctx *data = ctx;
if (hapd->wps) {
data->count++;
return wps_registrar_button_pushed(hapd->wps->registrar,
data->p2p_dev_addr);
}
return 0;
}
int hostapd_wps_button_pushed(struct hostapd_data *hapd,
const u8 *p2p_dev_addr)
{
return hostapd_wps_for_each(hapd, wps_button_pushed,
(void *) p2p_dev_addr);
struct wps_button_pushed_ctx ctx;
int ret;
os_memset(&ctx, 0, sizeof(ctx));
ctx.p2p_dev_addr = p2p_dev_addr;
ret = hostapd_wps_for_each(hapd, wps_button_pushed, &ctx);
if (ret == 0 && !ctx.count)
ret = -1;
return ret;
}
struct wps_cancel_ctx {
unsigned int count;
};
static int wps_cancel(struct hostapd_data *hapd, void *ctx)
{
if (hapd->wps == NULL)
return -1;
struct wps_cancel_ctx *data = ctx;
wps_registrar_wps_cancel(hapd->wps->registrar);
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
if (hapd->wps) {
data->count++;
wps_registrar_wps_cancel(hapd->wps->registrar);
ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
}
return 0;
}
@ -1316,7 +1358,14 @@ static int wps_cancel(struct hostapd_data *hapd, void *ctx)
int hostapd_wps_cancel(struct hostapd_data *hapd)
{
return hostapd_wps_for_each(hapd, wps_cancel, NULL);
struct wps_cancel_ctx ctx;
int ret;
os_memset(&ctx, 0, sizeof(ctx));
ret = hostapd_wps_for_each(hapd, wps_cancel, &ctx);
if (ret == 0 && !ctx.count)
ret = -1;
return ret;
}
@ -1546,6 +1595,10 @@ struct wps_ap_pin_data {
static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
{
struct wps_ap_pin_data *data = ctx;
if (!hapd->wps)
return 0;
os_free(hapd->conf->ap_pin);
hapd->conf->ap_pin = os_strdup(data->pin_txt);
#ifdef CONFIG_WPS_UPNP

View File

@ -51,6 +51,14 @@ int x_snoop_init(struct hostapd_data *hapd)
return -1;
}
#ifdef CONFIG_IPV6
if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
wpa_printf(MSG_DEBUG,
"x_snoop: Failed to enable multicast snooping on the bridge");
return -1;
}
#endif /* CONFIG_IPV6 */
return 0;
}

View File

@ -1,6 +1,6 @@
/*
* common module tests
* Copyright (c) 2014, Jouni Malinen <j@w1.fi>
* Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -10,6 +10,8 @@
#include "utils/common.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
#include "wpa_common.h"
@ -46,6 +48,10 @@ static const struct ieee802_11_parse_test_data parse_tests[] = {
{ (u8 *) "\x6e\x00", 2, ParseOK, 1 },
{ (u8 *) "\xc7\x00", 2, ParseOK, 1 },
{ (u8 *) "\xc7\x01\x00", 3, ParseOK, 1 },
{ (u8 *) "\x03\x00\x2a\x00\x36\x00\x37\x00\x38\x00\x2d\x00\x3d\x00\xbf\x00\xc0\x00",
18, ParseOK, 9 },
{ (u8 *) "\x8b\x00", 2, ParseOK, 1 },
{ (u8 *) "\xdd\x04\x00\x90\x4c\x04", 6, ParseUnknown, 1 },
{ NULL, 0, ParseOK, 0 }
};
@ -158,6 +164,34 @@ static int rsn_ie_parse_tests(void)
}
static int gas_tests(void)
{
struct wpabuf *buf;
wpa_printf(MSG_INFO, "gas tests");
gas_anqp_set_len(NULL);
buf = wpabuf_alloc(1);
if (buf == NULL)
return -1;
gas_anqp_set_len(buf);
wpabuf_free(buf);
buf = wpabuf_alloc(20);
if (buf == NULL)
return -1;
wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
wpabuf_put_u8(buf, 0);
wpabuf_put_be32(buf, 0);
wpabuf_put_u8(buf, 0);
gas_anqp_set_len(buf);
wpabuf_free(buf);
return 0;
}
int common_module_tests(void)
{
int ret = 0;
@ -165,6 +199,7 @@ int common_module_tests(void)
wpa_printf(MSG_INFO, "common module tests");
if (ieee802_11_parse_tests() < 0 ||
gas_tests() < 0 ||
rsn_ie_parse_tests() < 0)
ret = -1;

View File

@ -174,7 +174,7 @@ enum wpa_states {
/**
* WPA_INTERFACE_DISABLED - Interface disabled
*
* This stat eis entered if the network interface is disabled, e.g.,
* This state is 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.
*/
@ -295,6 +295,7 @@ enum hostapd_hw_mode {
HOSTAPD_MODE_IEEE80211G,
HOSTAPD_MODE_IEEE80211A,
HOSTAPD_MODE_IEEE80211AD,
HOSTAPD_MODE_IEEE80211ANY,
NUM_HOSTAPD_MODES
};
@ -310,6 +311,7 @@ enum wpa_ctrl_req_type {
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
WPA_CTRL_REQ_PSK_PASSPHRASE,
NUM_WPA_CTRL_REQS
};
@ -326,4 +328,10 @@ enum mesh_plink_state {
PLINK_BLOCKED,
};
enum set_band {
WPA_SETBAND_AUTO,
WPA_SETBAND_5G,
WPA_SETBAND_2G
};
#endif /* DEFS_H */

View File

@ -88,8 +88,8 @@ int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
int sec_chan)
{
int ok, j, first;
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
184, 192 };
int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
149, 157, 184, 192 };
size_t k;
if (pri_chan == sec_chan || !sec_chan)
@ -152,8 +152,7 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan)
*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)) {
if (elems.ht_operation) {
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
*pri_chan = oper->primary_chan;
if (oper->ht_param & HT_INFO_HT_PARAM_STA_CHNL_WIDTH) {
@ -177,10 +176,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
size_t i;
int match;
if (!mode || !scan_res || !pri_chan || !sec_chan)
return 0;
if (pri_chan == sec_chan)
if (!mode || !scan_res || !pri_chan || !sec_chan ||
pri_chan == sec_chan)
return 0;
pri_freq = hw_get_freq(mode, pri_chan);
@ -238,7 +235,8 @@ int check_40mhz_5g(struct hostapd_hw_modes *mode,
}
int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
static int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start,
int end)
{
struct ieee802_11_elems elems;
struct ieee80211_ht_operation *oper;
@ -253,8 +251,7 @@ int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
return 1;
}
if (elems.ht_operation &&
elems.ht_operation_len >= sizeof(*oper)) {
if (elems.ht_operation) {
oper = (struct ieee80211_ht_operation *) elems.ht_operation;
if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
return 0;
@ -275,10 +272,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int affected_start, affected_end;
size_t i;
if (!mode || !scan_res || !pri_chan || !sec_chan)
return 0;
if (pri_chan == sec_chan)
if (!mode || !scan_res || !pri_chan || !sec_chan ||
pri_chan == sec_chan)
return 0;
pri_freq = hw_get_freq(mode, pri_chan);
@ -335,9 +330,7 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
0);
if (elems.ht_capabilities &&
elems.ht_capabilities_len >=
sizeof(struct ieee80211_ht_capabilities)) {
if (elems.ht_capabilities) {
struct ieee80211_ht_capabilities *ht_cap =
(struct ieee80211_ht_capabilities *)
elems.ht_capabilities;
@ -363,8 +356,6 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
int vht_oper_chwidth, int center_segment0,
int center_segment1, u32 vht_caps)
{
int tmp;
os_memset(data, 0, sizeof(*data));
data->mode = mode;
data->freq = freq;
@ -378,11 +369,10 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
if (data->vht_enabled) switch (vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
if (center_segment1)
return -1;
if (center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
2407 + center_segment0 * 5 != data->center_freq1)
if (center_segment1 ||
(center_segment0 != 0 &&
5000 + center_segment0 * 5 != data->center_freq1 &&
2407 + center_segment0 * 5 != data->center_freq1))
return -1;
break;
case VHT_CHANWIDTH_80P80MHZ:
@ -398,19 +388,38 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
/* fall through */
case VHT_CHANWIDTH_80MHZ:
data->bandwidth = 80;
if (vht_oper_chwidth == 1 && center_segment1)
if ((vht_oper_chwidth == 1 && center_segment1) ||
(vht_oper_chwidth == 3 && !center_segment1) ||
!sec_channel_offset)
return -1;
if (vht_oper_chwidth == 3 && !center_segment1)
return -1;
if (!sec_channel_offset)
return -1;
/* primary 40 part must match the HT configuration */
tmp = (30 + freq - 5000 - center_segment0 * 5) / 20;
tmp /= 2;
if (data->center_freq1 != 5000 +
center_segment0 * 5 - 20 + 40 * tmp)
return -1;
data->center_freq1 = 5000 + center_segment0 * 5;
if (!center_segment0) {
if (channel <= 48)
center_segment0 = 42;
else if (channel <= 64)
center_segment0 = 58;
else if (channel <= 112)
center_segment0 = 106;
else if (channel <= 128)
center_segment0 = 122;
else if (channel <= 144)
center_segment0 = 138;
else if (channel <= 161)
center_segment0 = 155;
data->center_freq1 = 5000 + center_segment0 * 5;
} else {
/*
* Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT80 Pri channel band
* configuration.
*/
if (center_segment0 == channel + 6 ||
center_segment0 == channel + 2 ||
center_segment0 == channel - 2 ||
center_segment0 == channel - 6)
data->center_freq1 = 5000 + center_segment0 * 5;
else
return -1;
}
break;
case VHT_CHANWIDTH_160MHZ:
data->bandwidth = 160;
@ -424,13 +433,21 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
return -1;
if (!sec_channel_offset)
return -1;
/* primary 40 part must match the HT configuration */
tmp = (70 + freq - 5000 - center_segment0 * 5) / 20;
tmp /= 2;
if (data->center_freq1 != 5000 +
center_segment0 * 5 - 60 + 40 * tmp)
/*
* Note: HT/VHT config and params are coupled. Check if
* HT40 channel band is in VHT160 channel band configuration.
*/
if (center_segment0 == channel + 14 ||
center_segment0 == channel + 10 ||
center_segment0 == channel + 6 ||
center_segment0 == channel + 2 ||
center_segment0 == channel - 2 ||
center_segment0 == channel - 6 ||
center_segment0 == channel - 10 ||
center_segment0 == channel - 14)
data->center_freq1 = 5000 + center_segment0 * 5;
else
return -1;
data->center_freq1 = 5000 + center_segment0 * 5;
break;
}

View File

@ -26,7 +26,6 @@ void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
int check_40mhz_5g(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan);
int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end);
int check_40mhz_2g4(struct hostapd_hw_modes *mode,
struct wpa_scan_results *scan_res, int pri_chan,
int sec_chan);

View File

@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
* Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -10,6 +10,8 @@
#include "common.h"
#include "defs.h"
#include "wpa_common.h"
#include "qca-vendor.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
@ -146,6 +148,20 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
}
break;
case OUI_QCA:
switch (pos[3]) {
case QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST:
elems->pref_freq_list = pos;
elems->pref_freq_list_len = elen;
break;
default:
wpa_printf(MSG_EXCESSIVE,
"Unknown QCA 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 "
@ -196,6 +212,12 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
switch (id) {
case WLAN_EID_SSID:
if (elen > SSID_MAX_LEN) {
wpa_printf(MSG_DEBUG,
"Ignored too long SSID element (elen=%u)",
elen);
break;
}
elems->ssid = pos;
elems->ssid_len = elen;
break;
@ -204,8 +226,9 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->supp_rates_len = elen;
break;
case WLAN_EID_DS_PARAMS:
if (elen < 1)
break;
elems->ds_params = pos;
elems->ds_params_len = elen;
break;
case WLAN_EID_CF_PARAMS:
case WLAN_EID_TIM:
@ -215,8 +238,9 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->challenge_len = elen;
break;
case WLAN_EID_ERP_INFO:
if (elen < 1)
break;
elems->erp_info = pos;
elems->erp_info_len = elen;
break;
case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
@ -239,24 +263,31 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->supp_channels_len = elen;
break;
case WLAN_EID_MOBILITY_DOMAIN:
if (elen < sizeof(struct rsn_mdie))
break;
elems->mdie = pos;
elems->mdie_len = elen;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
if (elen < sizeof(struct rsn_ftie))
break;
elems->ftie = pos;
elems->ftie_len = elen;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
if (elen != 5)
break;
elems->timeout_int = pos;
elems->timeout_int_len = elen;
break;
case WLAN_EID_HT_CAP:
if (elen < sizeof(struct ieee80211_ht_capabilities))
break;
elems->ht_capabilities = pos;
elems->ht_capabilities_len = elen;
break;
case WLAN_EID_HT_OPERATION:
if (elen < sizeof(struct ieee80211_ht_operation))
break;
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
case WLAN_EID_MESH_CONFIG:
elems->mesh_config = pos;
@ -271,12 +302,14 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->peer_mgmt_len = elen;
break;
case WLAN_EID_VHT_CAP:
if (elen < sizeof(struct ieee80211_vht_capabilities))
break;
elems->vht_capabilities = pos;
elems->vht_capabilities_len = elen;
break;
case WLAN_EID_VHT_OPERATION:
if (elen < sizeof(struct ieee80211_vht_operation))
break;
elems->vht_operation = pos;
elems->vht_operation_len = elen;
break;
case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
if (elen != 1)
@ -321,6 +354,18 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
/* after mic everything is encrypted, so stop. */
left = elen;
break;
case WLAN_EID_MULTI_BAND:
if (elems->mb_ies.nof_ies >= MAX_NOF_MB_IES_SUPPORTED) {
wpa_printf(MSG_MSGDUMP,
"IEEE 802.11 element parse ignored MB IE (id=%d elen=%d)",
id, elen);
break;
}
elems->mb_ies.ies[elems->mb_ies.nof_ies].ie = pos;
elems->mb_ies.ies[elems->mb_ies.nof_ies].ie_len = elen;
elems->mb_ies.nof_ies++;
break;
default:
unknown++;
if (!show_errors)
@ -486,14 +531,14 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
ac->aifs = v;
} else if (os_strcmp(pos, "cwmin") == 0) {
v = atoi(val);
if (v < 0 || v > 12) {
if (v < 0 || v > 15) {
wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
return -1;
}
ac->cwmin = v;
} else if (os_strcmp(pos, "cwmax") == 0) {
v = atoi(val);
if (v < 0 || v > 12) {
if (v < 0 || v > 15) {
wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
return -1;
}
@ -523,50 +568,163 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel)
{
enum hostapd_hw_mode mode = NUM_HOSTAPD_MODES;
u8 op_class;
if (freq >= 2412 && freq <= 2472) {
mode = HOSTAPD_MODE_IEEE80211G;
*channel = (freq - 2407) / 5;
} else if (freq == 2484) {
mode = HOSTAPD_MODE_IEEE80211B;
*channel = 14;
} else if (freq >= 4900 && freq < 5000) {
mode = HOSTAPD_MODE_IEEE80211A;
*channel = (freq - 4000) / 5;
} else if (freq >= 5000 && freq < 5900) {
mode = HOSTAPD_MODE_IEEE80211A;
*channel = (freq - 5000) / 5;
} else if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
mode = HOSTAPD_MODE_IEEE80211AD;
*channel = (freq - 56160) / 2160;
}
return mode;
return ieee80211_freq_to_channel_ext(freq, 0, 0, &op_class, channel);
}
static const char *us_op_class_cc[] = {
/**
* ieee80211_freq_to_channel_ext - Convert frequency into channel info
* for HT40 and VHT. DFS channels are not covered.
* @freq: Frequency (MHz) to convert
* @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below
* @vht: 0 - non-VHT, 1 - 80 MHz
* @op_class: Buffer for returning operating class
* @channel: Buffer for returning channel number
* Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure
*/
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int sec_channel, int vht,
u8 *op_class, u8 *channel)
{
/* TODO: more operating classes */
if (sec_channel > 1 || sec_channel < -1)
return NUM_HOSTAPD_MODES;
if (freq >= 2412 && freq <= 2472) {
if ((freq - 2407) % 5)
return NUM_HOSTAPD_MODES;
if (vht)
return NUM_HOSTAPD_MODES;
/* 2.407 GHz, channels 1..13 */
if (sec_channel == 1)
*op_class = 83;
else if (sec_channel == -1)
*op_class = 84;
else
*op_class = 81;
*channel = (freq - 2407) / 5;
return HOSTAPD_MODE_IEEE80211G;
}
if (freq == 2484) {
if (sec_channel || vht)
return NUM_HOSTAPD_MODES;
*op_class = 82; /* channel 14 */
*channel = 14;
return HOSTAPD_MODE_IEEE80211B;
}
if (freq >= 4900 && freq < 5000) {
if ((freq - 4000) % 5)
return NUM_HOSTAPD_MODES;
*channel = (freq - 4000) / 5;
*op_class = 0; /* TODO */
return HOSTAPD_MODE_IEEE80211A;
}
/* 5 GHz, channels 36..48 */
if (freq >= 5180 && freq <= 5240) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
if (sec_channel == 1)
*op_class = 116;
else if (sec_channel == -1)
*op_class = 117;
else if (vht)
*op_class = 128;
else
*op_class = 115;
*channel = (freq - 5000) / 5;
return HOSTAPD_MODE_IEEE80211A;
}
/* 5 GHz, channels 149..161 */
if (freq >= 5745 && freq <= 5805) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
if (sec_channel == 1)
*op_class = 126;
else if (sec_channel == -1)
*op_class = 127;
else if (vht)
*op_class = 128;
else
*op_class = 124;
*channel = (freq - 5000) / 5;
return HOSTAPD_MODE_IEEE80211A;
}
/* 5 GHz, channels 149..169 */
if (freq >= 5745 && freq <= 5845) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
*op_class = 125;
*channel = (freq - 5000) / 5;
return HOSTAPD_MODE_IEEE80211A;
}
if (freq >= 5000 && freq < 5900) {
if ((freq - 5000) % 5)
return NUM_HOSTAPD_MODES;
*channel = (freq - 5000) / 5;
*op_class = 0; /* TODO */
return HOSTAPD_MODE_IEEE80211A;
}
/* 56.16 GHz, channel 1..4 */
if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 4) {
if (sec_channel || vht)
return NUM_HOSTAPD_MODES;
*channel = (freq - 56160) / 2160;
*op_class = 180;
return HOSTAPD_MODE_IEEE80211AD;
}
return NUM_HOSTAPD_MODES;
}
static const char *const us_op_class_cc[] = {
"US", "CA", NULL
};
static const char *eu_op_class_cc[] = {
static const char *const eu_op_class_cc[] = {
"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
};
static const char *jp_op_class_cc[] = {
static const char *const jp_op_class_cc[] = {
"JP", NULL
};
static const char *cn_op_class_cc[] = {
"CN", "CA", NULL
static const char *const cn_op_class_cc[] = {
"CN", NULL
};
static int country_match(const char *cc[], const char *country)
static int country_match(const char *const cc[], const char *const country)
{
int i;
@ -612,6 +770,10 @@ static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
case 5: /* channels 149,153,157,161,165 */
if (chan < 149 || chan > 165)
return -1;
return 5000 + 5 * chan;
case 34: /* 60 GHz band, channels 1..3 */
if (chan < 1 || chan > 3)
return -1;
@ -764,12 +926,15 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
return -1;
return 5000 + 5 * chan;
case 124: /* channels 149,153,157,161 */
case 125: /* channels 149,153,157,161,165,169 */
case 126: /* channels 149,157; 40 MHz */
case 127: /* channels 153,161; 40 MHz */
if (chan < 149 || chan > 161)
return -1;
return 5000 + 5 * chan;
case 125: /* channels 149,153,157,161,165,169 */
if (chan < 149 || chan > 169)
return -1;
return 5000 + 5 * chan;
case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
if (chan < 36 || chan > 161)
@ -921,3 +1086,62 @@ const char * fc2str(u16 fc)
return "WLAN_FC_TYPE_UNKNOWN";
#undef C2S
}
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len)
{
os_memset(info, 0, sizeof(*info));
while (ies_buf && ies_len >= 2 &&
info->nof_ies < MAX_NOF_MB_IES_SUPPORTED) {
size_t len = 2 + ies_buf[1];
if (len > ies_len) {
wpa_hexdump(MSG_DEBUG, "Truncated IEs",
ies_buf, ies_len);
return -1;
}
if (ies_buf[0] == WLAN_EID_MULTI_BAND) {
wpa_printf(MSG_DEBUG, "MB IE of %zu bytes found", len);
info->ies[info->nof_ies].ie = ies_buf + 2;
info->ies[info->nof_ies].ie_len = ies_buf[1];
info->nof_ies++;
}
ies_len -= len;
ies_buf += len;
}
return 0;
}
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info)
{
struct wpabuf *mb_ies = NULL;
WPA_ASSERT(info != NULL);
if (info->nof_ies) {
u8 i;
size_t mb_ies_size = 0;
for (i = 0; i < info->nof_ies; i++)
mb_ies_size += 2 + info->ies[i].ie_len;
mb_ies = wpabuf_alloc(mb_ies_size);
if (mb_ies) {
for (i = 0; i < info->nof_ies; i++) {
wpabuf_put_u8(mb_ies, WLAN_EID_MULTI_BAND);
wpabuf_put_u8(mb_ies, info->ies[i].ie_len);
wpabuf_put_data(mb_ies,
info->ies[i].ie,
info->ies[i].ie_len);
}
}
}
return mb_ies;
}

View File

@ -9,6 +9,16 @@
#ifndef IEEE802_11_COMMON_H
#define IEEE802_11_COMMON_H
#define MAX_NOF_MB_IES_SUPPORTED 5
struct mb_ies_info {
struct {
const u8 *ie;
u8 ie_len;
} ies[MAX_NOF_MB_IES_SUPPORTED];
u8 nof_ies;
};
/* Parsed Information Elements */
struct ieee802_11_elems {
const u8 *ssid;
@ -48,12 +58,11 @@ struct ieee802_11_elems {
const u8 *osen;
const u8 *ampe;
const u8 *mic;
const u8 *pref_freq_list;
u8 ssid_len;
u8 supp_rates_len;
u8 ds_params_len;
u8 challenge_len;
u8 erp_info_len;
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
@ -63,14 +72,9 @@ struct ieee802_11_elems {
u8 supp_channels_len;
u8 mdie_len;
u8 ftie_len;
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
u8 mesh_config_len;
u8 mesh_id_len;
u8 peer_mgmt_len;
u8 vht_capabilities_len;
u8 vht_operation_len;
u8 vendor_ht_cap_len;
u8 vendor_vht_len;
u8 p2p_len;
@ -83,6 +87,8 @@ struct ieee802_11_elems {
u8 osen_len;
u8 ampe_len;
u8 mic_len;
u8 pref_freq_list_len;
struct mb_ies_info mb_ies;
};
typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@ -108,9 +114,15 @@ int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
int sec_channel, int vht,
u8 *op_class, u8 *channel);
int ieee80211_is_dfs(int freq);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
int mb_ies_info_by_ies(struct mb_ies_info *info, const u8 *ies_buf,
size_t ies_len);
struct wpabuf * mb_ies_by_info(struct mb_ies_info *info);
const char * fc2str(u16 fc);
#endif /* IEEE802_11_COMMON_H */

View File

@ -10,6 +10,8 @@
#ifndef IEEE802_11_DEFS_H
#define IEEE802_11_DEFS_H
#include <utils/common.h>
/* IEEE 802.11 defines */
#define WLAN_FC_PVER 0x0003
@ -163,7 +165,10 @@
#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
#define WLAN_STATUS_TRANSMISSION_FAILURE 79
#define WLAN_STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION 82
#define WLAN_STATUS_PENDING_ADMITTING_FST_SESSION 86
#define WLAN_STATUS_QUERY_RESP_OUTSTANDING 95
#define WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL 99
#define WLAN_STATUS_ASSOC_DENIED_NO_VHT 104
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
@ -269,6 +274,8 @@
#define WLAN_EID_AMPE 139
#define WLAN_EID_MIC 140
#define WLAN_EID_CCKM 156
#define WLAN_EID_MULTI_BAND 158
#define WLAN_EID_SESSION_TRANSITION 164
#define WLAN_EID_VHT_CAP 191
#define WLAN_EID_VHT_OPERATION 192
#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
@ -297,6 +304,7 @@
#define WLAN_ACTION_TDLS 12
#define WLAN_ACTION_SELF_PROTECTED 15
#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
#define WLAN_ACTION_FST 18
#define WLAN_ACTION_VENDOR_SPECIFIC 127
/* Public action codes */
@ -470,35 +478,35 @@ struct ieee80211_mgmt {
le16 auth_transaction;
le16 status_code;
/* possibly followed by Challenge text */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED auth;
struct {
le16 reason_code;
u8 variable[0];
u8 variable[];
} STRUCT_PACKED deauth;
struct {
le16 capab_info;
le16 listen_interval;
/* followed by SSID and Supported rates */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED assoc_req;
struct {
le16 capab_info;
le16 status_code;
le16 aid;
/* followed by Supported rates */
u8 variable[0];
u8 variable[];
} 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];
u8 variable[];
} STRUCT_PACKED reassoc_req;
struct {
le16 reason_code;
u8 variable[0];
u8 variable[];
} STRUCT_PACKED disassoc;
struct {
u8 timestamp[8];
@ -506,7 +514,7 @@ struct ieee80211_mgmt {
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED beacon;
struct {
/* only variable items: SSID, Supported rates */
@ -518,7 +526,7 @@ struct ieee80211_mgmt {
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED probe_resp;
struct {
u8 category;
@ -527,7 +535,7 @@ struct ieee80211_mgmt {
u8 action_code;
u8 dialog_token;
u8 status_code;
u8 variable[0];
u8 variable[];
} STRUCT_PACKED wmm_action;
struct{
u8 action_code;
@ -541,14 +549,14 @@ struct ieee80211_mgmt {
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
u8 variable[0]; /* FT Request */
u8 variable[]; /* 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 */
u8 variable[]; /* FT Request */
} STRUCT_PACKED ft_action_resp;
struct {
u8 action;
@ -561,23 +569,23 @@ struct ieee80211_mgmt {
struct {
u8 action;
u8 dialogtoken;
u8 variable[0];
u8 variable[];
} STRUCT_PACKED wnm_sleep_req;
struct {
u8 action;
u8 dialogtoken;
le16 keydata_len;
u8 variable[0];
u8 variable[];
} STRUCT_PACKED wnm_sleep_resp;
struct {
u8 action;
u8 variable[0];
u8 variable[];
} STRUCT_PACKED public_action;
struct {
u8 action; /* 9 */
u8 oui[3];
/* Vendor-specific content */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED vs_public_action;
struct {
u8 action; /* 7 */
@ -589,7 +597,7 @@ struct ieee80211_mgmt {
* Session Information URL (optional),
* BSS Transition Candidate List
* Entries */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED bss_tm_req;
struct {
u8 action; /* 8 */
@ -599,7 +607,7 @@ struct ieee80211_mgmt {
/* Target BSSID (optional),
* BSS Transition Candidate List
* Entries (optional) */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED bss_tm_resp;
struct {
u8 action; /* 6 */
@ -607,12 +615,16 @@ struct ieee80211_mgmt {
u8 query_reason;
/* BSS Transition Candidate List
* Entries (optional) */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED bss_tm_query;
struct {
u8 action; /* 15 */
u8 variable[0];
u8 variable[];
} STRUCT_PACKED slf_prot_action;
struct {
u8 action;
u8 variable[];
} STRUCT_PACKED fst_action;
} u;
} STRUCT_PACKED action;
} u;
@ -1065,6 +1077,15 @@ enum p2p_attr_id {
#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
#define P2P_GROUP_CAPAB_IP_ADDR_ALLOCATION BIT(7)
/* P2PS Coordination Protocol Transport Bitmap */
#define P2PS_FEATURE_CAPAB_UDP_TRANSPORT BIT(0)
#define P2PS_FEATURE_CAPAB_MAC_TRANSPORT BIT(1)
struct p2ps_feature_capab {
u8 cpt;
u8 reserved;
} STRUCT_PACKED;
/* Invitation Flags */
#define P2P_INVITATION_FLAGS_TYPE BIT(0)
@ -1354,4 +1375,62 @@ struct rrm_link_measurement_report {
u8 variable[0];
} STRUCT_PACKED;
#define SSID_MAX_LEN 32
/* IEEE Std 802.11ad-2012 - Multi-band element */
struct multi_band_ie {
u8 eid; /* WLAN_EID_MULTI_BAND */
u8 len;
u8 mb_ctrl;
u8 band_id;
u8 op_class;
u8 chan;
u8 bssid[ETH_ALEN];
le16 beacon_int;
u8 tsf_offs[8];
u8 mb_connection_capability;
u8 fst_session_tmout;
/* Optional:
* STA MAC Address
* Pairwise Cipher Suite Count
* Pairwise Cipher Suite List
*/
u8 variable[0];
} STRUCT_PACKED;
enum mb_ctrl_sta_role {
MB_STA_ROLE_AP = 0,
MB_STA_ROLE_TDLS_STA = 1,
MB_STA_ROLE_IBSS_STA = 2,
MB_STA_ROLE_PCP = 3,
MB_STA_ROLE_NON_PCP_NON_AP = 4
};
#define MB_CTRL_ROLE_MASK (BIT(0) | BIT(1) | BIT(2))
#define MB_CTRL_ROLE(ctrl) ((u8) ((ctrl) & MB_CTRL_ROLE_MASK))
#define MB_CTRL_STA_MAC_PRESENT ((u8) (BIT(3)))
#define MB_CTRL_PAIRWISE_CIPHER_SUITE_PRESENT ((u8) (BIT(4)))
enum mb_band_id {
MB_BAND_ID_WIFI_2_4GHZ = 2, /* 2.4 GHz */
MB_BAND_ID_WIFI_5GHZ = 4, /* 4.9 and 5 GHz */
MB_BAND_ID_WIFI_60GHZ = 5, /* 60 GHz */
};
#define MB_CONNECTION_CAPABILITY_AP ((u8) (BIT(0)))
#define MB_CONNECTION_CAPABILITY_PCP ((u8) (BIT(1)))
#define MB_CONNECTION_CAPABILITY_DLS ((u8) (BIT(2)))
#define MB_CONNECTION_CAPABILITY_TDLS ((u8) (BIT(3)))
#define MB_CONNECTION_CAPABILITY_IBSS ((u8) (BIT(4)))
/* IEEE Std 802.11ad-2014 - FST Action field */
enum fst_action {
FST_ACTION_SETUP_REQUEST = 0,
FST_ACTION_SETUP_RESPONSE = 1,
FST_ACTION_TEAR_DOWN = 2,
FST_ACTION_ACK_REQUEST = 3,
FST_ACTION_ACK_RESPONSE = 4,
FST_ACTION_ON_CHANNEL_TUNNEL = 5,
};
#endif /* IEEE802_11_DEFS_H */

View File

@ -9,6 +9,8 @@
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
#include "common/ieee802_11_defs.h"
enum privsep_cmd {
PRIVSEP_CMD_REGISTER,
PRIVSEP_CMD_UNREGISTER,
@ -24,12 +26,31 @@ enum privsep_cmd {
PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
PRIVSEP_CMD_L2_SEND,
PRIVSEP_CMD_SET_COUNTRY,
PRIVSEP_CMD_AUTHENTICATE,
};
struct privsep_cmd_authenticate
{
int freq;
u8 bssid[ETH_ALEN];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int auth_alg;
size_t ie_len;
u8 wep_key[4][16];
size_t wep_key_len[4];
int wep_tx_keyidx;
int local_state_change;
int p2p;
size_t sae_data_len;
/* followed by ie_len bytes of ie */
/* followed by sae_data_len bytes of sae_data */
};
struct privsep_cmd_associate
{
u8 bssid[ETH_ALEN];
u8 ssid[32];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int hwmode;
int freq;
@ -66,6 +87,18 @@ enum privsep_event {
PRIVSEP_EVENT_STKSTART,
PRIVSEP_EVENT_FT_RESPONSE,
PRIVSEP_EVENT_RX_EAPOL,
PRIVSEP_EVENT_SCAN_STARTED,
PRIVSEP_EVENT_AUTH,
};
struct privsep_event_auth {
u8 peer[ETH_ALEN];
u8 bssid[ETH_ALEN];
u16 auth_type;
u16 auth_transaction;
u16 status_code;
size_t ies_len;
/* followed by ies_len bytes of ies */
};
#endif /* PRIVSEP_COMMANDS_H */

View File

@ -132,7 +132,7 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
/* 53 - reserved for QCA */
/* 53 - reserved - was used by QCA, but not in use anymore */
QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56,
@ -142,6 +142,20 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
/* 61-90 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94,
QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95,
QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96,
QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97,
QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98,
QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99,
QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100,
QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101,
QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG = 102,
QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103,
QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104,
QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105,
};
@ -162,6 +176,15 @@ enum qca_wlan_vendor_attr {
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
QCA_WLAN_VENDOR_ATTR_TEST = 8,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
/* Unsigned 32-bit value. */
QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA = 9,
/* Unsigned 32-bit value */
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10,
/* Unsigned 32-bit value */
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11,
/* Unsigned 32-bit value from enum qca_set_band. */
QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@ -195,6 +218,12 @@ enum qca_wlan_vendor_attr_acs_offload {
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
@ -206,6 +235,7 @@ enum qca_wlan_vendor_acs_hw_mode {
QCA_ACS_MODE_IEEE80211G,
QCA_ACS_MODE_IEEE80211A,
QCA_ACS_MODE_IEEE80211AD,
QCA_ACS_MODE_IEEE80211ANY,
};
/**
@ -215,10 +245,13 @@ enum qca_wlan_vendor_acs_hw_mode {
* management offload, a mechanism where the station's firmware
* does the exchange with the AP to establish the temporal keys
* after roaming, rather than having the user space wpa_supplicant do it.
* @QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY: Device supports automatic
* band selection based on channel selection results.
* @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
*/
enum qca_wlan_vendor_features {
QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0,
QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1,
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
@ -243,4 +276,82 @@ enum qca_wlan_vendor_attr_data_offload_ind {
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_MAX =
QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
};
enum qca_vendor_attr_get_preferred_freq_list {
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID,
/* A 32-unsigned value; the interface type/mode for which the preferred
* frequency list is requested (see enum qca_iface_type for possible
* values); used in GET_PREFERRED_FREQ_LIST command from user-space to
* kernel and in the kernel response back to user-space.
*/
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
/* An array of 32-unsigned values; values are frequency (MHz); sent
* from kernel space to user space.
*/
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST,
/* keep last */
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX =
QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST - 1
};
enum qca_vendor_attr_probable_oper_channel {
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID,
/* 32-bit unsigned value; indicates the connection/iface type likely to
* come on this channel (see enum qca_iface_type).
*/
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
/* 32-bit unsigned value; the frequency (MHz) of the probable channel */
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
/* keep last */
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX =
QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST - 1
};
enum qca_iface_type {
QCA_IFACE_TYPE_STA,
QCA_IFACE_TYPE_AP,
QCA_IFACE_TYPE_P2P_CLIENT,
QCA_IFACE_TYPE_P2P_GO,
QCA_IFACE_TYPE_IBSS,
QCA_IFACE_TYPE_TDLS,
};
enum qca_set_band {
QCA_SETBAND_AUTO,
QCA_SETBAND_5G,
QCA_SETBAND_2G,
};
/* IEEE 802.11 Vendor Specific elements */
/**
* enum qca_vendor_element_id - QCA Vendor Specific element types
*
* These values are used to identify QCA Vendor Specific elements. The
* payload of the element starts with the three octet OUI (OUI_QCA) and
* is followed by a single octet type which is defined by this enum.
*
* @QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST: P2P preferred channel list.
* This element can be used to specify preference order for supported
* channels. The channels in this list are in preference order (the first
* one has the highest preference) and are described as a pair of
* (global) Operating Class and Channel Number (each one octet) fields.
*
* This extends the standard P2P functionality by providing option to have
* more than one preferred operating channel. When this element is present,
* it replaces the preference indicated in the Operating Channel attribute.
* For supporting other implementations, the Operating Channel attribute is
* expected to be used with the highest preference channel. Similarly, all
* the channels included in this Preferred channel list element are
* expected to be included in the Channel List attribute.
*
* This vendor element may be included in GO Negotiation Request, P2P
* Invitation Request, and Provision Discovery Request frames.
*/
enum qca_vendor_element_id {
QCA_VENDOR_ELEM_P2P_PREF_CHAN_LIST = 0,
};
#endif /* QCA_VENDOR_H */

View File

@ -1,6 +1,6 @@
/*
* Simultaneous authentication of equals
* Copyright (c) 2012-2013, Jouni Malinen <j@w1.fi>
* Copyright (c) 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@ -124,9 +124,7 @@ static struct crypto_bignum * sae_get_rand(struct sae_data *sae)
return NULL;
for (;;) {
if (iter++ > 100)
return NULL;
if (random_get_bytes(val, order_len) < 0)
if (iter++ > 100 || random_get_bytes(val, order_len) < 0)
return NULL;
if (order_len_bits % 8)
buf_shift_right(val, order_len, 8 - order_len_bits % 8);
@ -171,17 +169,107 @@ static void sae_pwd_seed_key(const u8 *addr1, const u8 *addr2, u8 *key)
}
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
struct crypto_ec_point *pwe)
static struct crypto_bignum *
get_rand_1_to_p_1(const u8 *prime, size_t prime_len, size_t prime_bits,
int *r_odd)
{
u8 pwd_value[SAE_MAX_ECC_PRIME_LEN], prime[SAE_MAX_ECC_PRIME_LEN];
struct crypto_bignum *x;
int y_bit;
for (;;) {
struct crypto_bignum *r;
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
if (random_get_bytes(tmp, prime_len) < 0)
break;
if (prime_bits % 8)
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
if (os_memcmp(tmp, prime, prime_len) >= 0)
continue;
r = crypto_bignum_init_set(tmp, prime_len);
if (!r)
break;
if (crypto_bignum_is_zero(r)) {
crypto_bignum_deinit(r, 0);
continue;
}
*r_odd = tmp[prime_len - 1] & 0x01;
return r;
}
return NULL;
}
static int is_quadratic_residue_blind(struct sae_data *sae,
const u8 *prime, size_t bits,
const struct crypto_bignum *qr,
const struct crypto_bignum *qnr,
const struct crypto_bignum *y_sqr)
{
struct crypto_bignum *r, *num;
int r_odd, check, res = -1;
/*
* Use the blinding technique to mask y_sqr while determining
* whether it is a quadratic residue modulo p to avoid leaking
* timing information while determining the Legendre symbol.
*
* v = y_sqr
* r = a random number between 1 and p-1, inclusive
* num = (v * r * r) modulo p
*/
r = get_rand_1_to_p_1(prime, sae->tmp->prime_len, bits, &r_odd);
if (!r)
return -1;
num = crypto_bignum_init();
if (!num ||
crypto_bignum_mulmod(y_sqr, r, sae->tmp->prime, num) < 0 ||
crypto_bignum_mulmod(num, r, sae->tmp->prime, num) < 0)
goto fail;
if (r_odd) {
/*
* num = (num * qr) module p
* LGR(num, p) = 1 ==> quadratic residue
*/
if (crypto_bignum_mulmod(num, qr, sae->tmp->prime, num) < 0)
goto fail;
check = 1;
} else {
/*
* num = (num * qnr) module p
* LGR(num, p) = -1 ==> quadratic residue
*/
if (crypto_bignum_mulmod(num, qnr, sae->tmp->prime, num) < 0)
goto fail;
check = -1;
}
res = crypto_bignum_legendre(num, sae->tmp->prime);
if (res == -2) {
res = -1;
goto fail;
}
res = res == check;
fail:
crypto_bignum_deinit(num, 1);
crypto_bignum_deinit(r, 1);
return res;
}
static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
const u8 *prime,
const struct crypto_bignum *qr,
const struct crypto_bignum *qnr,
struct crypto_bignum **ret_x_cand)
{
u8 pwd_value[SAE_MAX_ECC_PRIME_LEN];
struct crypto_bignum *y_sqr, *x_cand;
int res;
size_t bits;
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
sae->tmp->prime_len) < 0)
return -1;
*ret_x_cand = NULL;
wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, SHA256_MAC_LEN);
@ -197,20 +285,23 @@ static int sae_test_pwd_seed_ecc(struct sae_data *sae, const u8 *pwd_seed,
if (os_memcmp(pwd_value, prime, sae->tmp->prime_len) >= 0)
return 0;
y_bit = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
x = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
if (x == NULL)
x_cand = crypto_bignum_init_set(pwd_value, sae->tmp->prime_len);
if (!x_cand)
return -1;
y_sqr = crypto_ec_point_compute_y_sqr(sae->tmp->ec, x_cand);
if (!y_sqr) {
crypto_bignum_deinit(x_cand, 1);
return -1;
if (crypto_ec_point_solve_y_coord(sae->tmp->ec, pwe, x, y_bit) < 0) {
crypto_bignum_deinit(x, 0);
wpa_printf(MSG_DEBUG, "SAE: No solution found");
return 0;
}
crypto_bignum_deinit(x, 0);
wpa_printf(MSG_DEBUG, "SAE: PWE found");
res = is_quadratic_residue_blind(sae, prime, bits, qr, qnr, y_sqr);
crypto_bignum_deinit(y_sqr, 1);
if (res <= 0) {
crypto_bignum_deinit(x_cand, 1);
return res;
}
*ret_x_cand = x_cand;
return 1;
}
@ -288,24 +379,77 @@ static int sae_test_pwd_seed_ffc(struct sae_data *sae, const u8 *pwd_seed,
}
static int get_random_qr_qnr(const u8 *prime, size_t prime_len,
const struct crypto_bignum *prime_bn,
size_t prime_bits, struct crypto_bignum **qr,
struct crypto_bignum **qnr)
{
*qr = NULL;
*qnr = NULL;
while (!(*qr) || !(*qnr)) {
u8 tmp[SAE_MAX_ECC_PRIME_LEN];
struct crypto_bignum *q;
int res;
if (random_get_bytes(tmp, prime_len) < 0)
break;
if (prime_bits % 8)
buf_shift_right(tmp, prime_len, 8 - prime_bits % 8);
if (os_memcmp(tmp, prime, prime_len) >= 0)
continue;
q = crypto_bignum_init_set(tmp, prime_len);
if (!q)
break;
res = crypto_bignum_legendre(q, prime_bn);
if (res == 1 && !(*qr))
*qr = q;
else if (res == -1 && !(*qnr))
*qnr = q;
else
crypto_bignum_deinit(q, 0);
}
return (*qr && *qnr) ? 0 : -1;
}
static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
const u8 *addr2, const u8 *password,
size_t password_len)
{
u8 counter, k = 4;
u8 counter, k = 40;
u8 addrs[2 * ETH_ALEN];
const u8 *addr[2];
size_t len[2];
int found = 0;
struct crypto_ec_point *pwe_tmp;
u8 dummy_password[32];
size_t dummy_password_len;
int pwd_seed_odd = 0;
u8 prime[SAE_MAX_ECC_PRIME_LEN];
size_t prime_len;
struct crypto_bignum *x = NULL, *qr, *qnr;
size_t bits;
int res;
if (sae->tmp->pwe_ecc == NULL) {
sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
if (sae->tmp->pwe_ecc == NULL)
return -1;
}
pwe_tmp = crypto_ec_point_init(sae->tmp->ec);
if (pwe_tmp == NULL)
dummy_password_len = password_len;
if (dummy_password_len > sizeof(dummy_password))
dummy_password_len = sizeof(dummy_password);
if (random_get_bytes(dummy_password, dummy_password_len) < 0)
return -1;
prime_len = sae->tmp->prime_len;
if (crypto_bignum_to_bin(sae->tmp->prime, prime, sizeof(prime),
prime_len) < 0)
return -1;
bits = crypto_ec_prime_len_bits(sae->tmp->ec);
/*
* Create a random quadratic residue (qr) and quadratic non-residue
* (qnr) modulo p for blinding purposes during the loop.
*/
if (get_random_qr_qnr(prime, prime_len, sae->tmp->prime, bits,
&qr, &qnr) < 0)
return -1;
wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
@ -313,8 +457,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
/*
* H(salt, ikm) = HMAC-SHA256(salt, ikm)
* base = password
* pwd-seed = H(MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC),
* password || counter)
* base || counter)
*/
sae_pwd_seed_key(addr1, addr2, addrs);
@ -328,9 +473,9 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
* attacks that attempt to determine the number of iterations required
* in the loop.
*/
for (counter = 1; counter < k || !found; counter++) {
for (counter = 1; counter <= k || !x; counter++) {
u8 pwd_seed[SHA256_MAC_LEN];
int res;
struct crypto_bignum *x_cand;
if (counter > 200) {
/* This should not happen in practice */
@ -342,25 +487,58 @@ static int sae_derive_pwe_ecc(struct sae_data *sae, const u8 *addr1,
if (hmac_sha256_vector(addrs, sizeof(addrs), 2, addr, len,
pwd_seed) < 0)
break;
res = sae_test_pwd_seed_ecc(sae, pwd_seed,
found ? pwe_tmp :
sae->tmp->pwe_ecc);
prime, qr, qnr, &x_cand);
if (res < 0)
break;
if (res == 0)
continue;
if (found) {
wpa_printf(MSG_DEBUG, "SAE: Ignore this PWE (one was "
"already selected)");
} else {
wpa_printf(MSG_DEBUG, "SAE: Use this PWE");
found = 1;
goto fail;
if (res > 0 && !x) {
wpa_printf(MSG_DEBUG,
"SAE: Selected pwd-seed with counter %u",
counter);
x = x_cand;
pwd_seed_odd = pwd_seed[SHA256_MAC_LEN - 1] & 0x01;
os_memset(pwd_seed, 0, sizeof(pwd_seed));
/*
* Use a dummy password for the following rounds, if
* any.
*/
addr[0] = dummy_password;
len[0] = dummy_password_len;
} else if (res > 0) {
crypto_bignum_deinit(x_cand, 1);
}
}
crypto_ec_point_deinit(pwe_tmp, 1);
if (!x) {
wpa_printf(MSG_DEBUG, "SAE: Could not generate PWE");
res = -1;
goto fail;
}
return found ? 0 : -1;
if (!sae->tmp->pwe_ecc)
sae->tmp->pwe_ecc = crypto_ec_point_init(sae->tmp->ec);
if (!sae->tmp->pwe_ecc)
res = -1;
else
res = crypto_ec_point_solve_y_coord(sae->tmp->ec,
sae->tmp->pwe_ecc, x,
pwd_seed_odd);
crypto_bignum_deinit(x, 1);
if (res < 0) {
/*
* This should not happen since we already checked that there
* is a result.
*/
wpa_printf(MSG_DEBUG, "SAE: Could not solve y");
}
fail:
crypto_bignum_deinit(qr, 0);
crypto_bignum_deinit(qnr, 0);
return res;
}
@ -472,27 +650,41 @@ static int sae_derive_commit(struct sae_data *sae)
{
struct crypto_bignum *mask;
int ret = -1;
unsigned int counter = 0;
mask = sae_get_rand_and_mask(sae);
if (mask == NULL) {
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
return -1;
}
do {
counter++;
if (counter > 100) {
/*
* This cannot really happen in practice if the random
* number generator is working. Anyway, to avoid even a
* theoretical infinite loop, break out after 100
* attemps.
*/
return -1;
}
/* commit-scalar = (rand + mask) modulo r */
if (!sae->tmp->own_commit_scalar) {
sae->tmp->own_commit_scalar = crypto_bignum_init();
if (!sae->tmp->own_commit_scalar)
goto fail;
}
crypto_bignum_add(sae->tmp->sae_rand, mask,
sae->tmp->own_commit_scalar);
crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
sae->tmp->own_commit_scalar);
mask = sae_get_rand_and_mask(sae);
if (mask == NULL) {
wpa_printf(MSG_DEBUG, "SAE: Could not get rand/mask");
return -1;
}
if (sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0)
goto fail;
if (sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0)
/* commit-scalar = (rand + mask) modulo r */
if (!sae->tmp->own_commit_scalar) {
sae->tmp->own_commit_scalar = crypto_bignum_init();
if (!sae->tmp->own_commit_scalar)
goto fail;
}
crypto_bignum_add(sae->tmp->sae_rand, mask,
sae->tmp->own_commit_scalar);
crypto_bignum_mod(sae->tmp->own_commit_scalar, sae->tmp->order,
sae->tmp->own_commit_scalar);
} while (crypto_bignum_is_zero(sae->tmp->own_commit_scalar) ||
crypto_bignum_is_one(sae->tmp->own_commit_scalar));
if ((sae->tmp->ec && sae_derive_commit_element_ecc(sae, mask) < 0) ||
(sae->tmp->dh && sae_derive_commit_element_ffc(sae, mask) < 0))
goto fail;
ret = 0;
@ -506,15 +698,12 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
struct sae_data *sae)
{
if (sae->tmp == NULL)
return -1;
if (sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
password_len) < 0)
return -1;
if (sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
password_len) < 0)
return -1;
if (sae_derive_commit(sae) < 0)
if (sae->tmp == NULL ||
(sae->tmp->ec && sae_derive_pwe_ecc(sae, addr1, addr2, password,
password_len) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
password_len) < 0) ||
sae_derive_commit(sae) < 0)
return -1;
return 0;
}
@ -780,8 +969,9 @@ static u16 sae_parse_commit_scalar(struct sae_data *sae, const u8 **pos,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
/* 0 < scalar < r */
/* 1 < scalar < r */
if (crypto_bignum_is_zero(peer_scalar) ||
crypto_bignum_is_one(peer_scalar) ||
crypto_bignum_cmp(peer_scalar, sae->tmp->order) >= 0) {
wpa_printf(MSG_DEBUG, "SAE: Invalid peer scalar");
crypto_bignum_deinit(peer_scalar, 0);
@ -847,7 +1037,8 @@ static u16 sae_parse_commit_element_ecc(struct sae_data *sae, const u8 *pos,
static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
const u8 *end)
{
struct crypto_bignum *res;
struct crypto_bignum *res, *one;
const u8 one_bin[1] = { 0x01 };
if (pos + sae->tmp->prime_len > end) {
wpa_printf(MSG_DEBUG, "SAE: Not enough data for "
@ -862,18 +1053,23 @@ static u16 sae_parse_commit_element_ffc(struct sae_data *sae, const u8 *pos,
crypto_bignum_init_set(pos, sae->tmp->prime_len);
if (sae->tmp->peer_commit_element_ffc == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
if (crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
/* 1 < element < p - 1 */
res = crypto_bignum_init();
one = crypto_bignum_init_set(one_bin, sizeof(one_bin));
if (!res || !one ||
crypto_bignum_sub(sae->tmp->prime, one, res) ||
crypto_bignum_is_zero(sae->tmp->peer_commit_element_ffc) ||
crypto_bignum_is_one(sae->tmp->peer_commit_element_ffc) ||
crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc,
sae->tmp->prime) >= 0) {
crypto_bignum_cmp(sae->tmp->peer_commit_element_ffc, res) >= 0) {
crypto_bignum_deinit(res, 0);
crypto_bignum_deinit(one, 0);
wpa_printf(MSG_DEBUG, "SAE: Invalid peer element");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
crypto_bignum_deinit(one, 0);
/* scalar-op(r, ELEMENT) = 1 modulo p */
res = crypto_bignum_init();
if (res == NULL ||
crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
if (crypto_bignum_exptmod(sae->tmp->peer_commit_element_ffc,
sae->tmp->order, sae->tmp->prime, res) < 0 ||
!crypto_bignum_is_one(res)) {
wpa_printf(MSG_DEBUG, "SAE: Invalid peer element (scalar-op)");
@ -918,7 +1114,34 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res;
/* commit-element */
return sae_parse_commit_element(sae, pos, end);
res = sae_parse_commit_element(sae, pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
*/
if (!sae->tmp->own_commit_scalar ||
crypto_bignum_cmp(sae->tmp->own_commit_scalar,
sae->peer_commit_scalar) != 0 ||
(sae->tmp->dh &&
(!sae->tmp->own_commit_element_ffc ||
crypto_bignum_cmp(sae->tmp->own_commit_element_ffc,
sae->tmp->peer_commit_element_ffc) != 0)) ||
(sae->tmp->ec &&
(!sae->tmp->own_commit_element_ecc ||
crypto_ec_point_cmp(sae->tmp->ec,
sae->tmp->own_commit_element_ecc,
sae->tmp->peer_commit_element_ecc) != 0)))
return WLAN_STATUS_SUCCESS; /* scalars/elements are different */
/*
* This is a reflection attack - return special value to trigger caller
* to silently discard the frame instead of replying with a specific
* status code.
*/
return SAE_SILENTLY_DISCARD;
}

View File

@ -18,6 +18,9 @@
#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
struct sae_temporary_data {
u8 kck[SAE_KCK_LEN];
struct crypto_bignum *own_commit_scalar;

View File

@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
#define VERSION_STR "2.4" VERSION_STR_POSTFIX
#define VERSION_STR "2.5" VERSION_STR_POSTFIX
#endif /* VERSION_H */

View File

@ -170,6 +170,12 @@ int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
ptk->tk_len = wpa_cipher_key_len(cipher);
ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
#ifdef CONFIG_SUITEB192
if (wpa_key_mgmt_sha384(akmp))
sha384_prf(pmk, pmk_len, label, data, sizeof(data),
tmp, ptk_len);
else
#endif /* CONFIG_SUITEB192 */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
@ -207,8 +213,10 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
{
u8 *buf, *pos;
size_t buf_len;
const u8 *addr[9];
size_t len[9];
size_t i, num_elem = 0;
u8 zero_mic[16];
if (kck_len != 16) {
wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
@ -216,48 +224,58 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
return -1;
}
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
addr[num_elem] = sta_addr;
len[num_elem] = ETH_ALEN;
num_elem++;
addr[num_elem] = ap_addr;
len[num_elem] = ETH_ALEN;
num_elem++;
addr[num_elem] = &transaction_seqnum;
len[num_elem] = 1;
num_elem++;
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;
addr[num_elem] = rsnie;
len[num_elem] = rsnie_len;
num_elem++;
}
if (mdie) {
os_memcpy(pos, mdie, mdie_len);
pos += mdie_len;
addr[num_elem] = mdie;
len[num_elem] = mdie_len;
num_elem++;
}
if (ftie) {
struct rsn_ftie *_ftie;
os_memcpy(pos, ftie, ftie_len);
if (ftie_len < 2 + sizeof(*_ftie)) {
os_free(buf);
if (ftie_len < 2 + sizeof(struct rsn_ftie))
return -1;
}
_ftie = (struct rsn_ftie *) (pos + 2);
os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
pos += ftie_len;
/* IE hdr and mic_control */
addr[num_elem] = ftie;
len[num_elem] = 2 + 2;
num_elem++;
/* MIC field with all zeros */
os_memset(zero_mic, 0, sizeof(zero_mic));
addr[num_elem] = zero_mic;
len[num_elem] = sizeof(zero_mic);
num_elem++;
/* Rest of FTIE */
addr[num_elem] = ftie + 2 + 2 + 16;
len[num_elem] = ftie_len - (2 + 2 + 16);
num_elem++;
}
if (ric) {
os_memcpy(pos, ric, ric_len);
pos += ric_len;
addr[num_elem] = ric;
len[num_elem] = ric_len;
num_elem++;
}
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
if (omac1_aes_128(kck, buf, pos - buf, mic)) {
os_free(buf);
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
return -1;
}
os_free(buf);
return 0;
}
@ -344,6 +362,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
parse->rsn_pmkid = data.pmkid;
break;
case WLAN_EID_MOBILITY_DOMAIN:
if (pos[1] < sizeof(struct rsn_mdie))
return -1;
parse->mdie = pos + 2;
parse->mdie_len = pos[1];
break;
@ -356,6 +376,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
return -1;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
if (pos[1] != 5)
break;
parse->tie = pos + 2;
parse->tie_len = pos[1];
break;
@ -416,14 +438,10 @@ 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;
@ -474,15 +492,15 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
return WPA_KEY_MGMT_OSEN;
return 0;
}
static int wpa_cipher_valid_group(int cipher)
int wpa_cipher_valid_group(int cipher)
{
return wpa_cipher_valid_pairwise(cipher) ||
cipher == WPA_CIPHER_WEP104 ||
cipher == WPA_CIPHER_WEP40 ||
cipher == WPA_CIPHER_GTK_NOT_USED;
}
@ -508,7 +526,6 @@ int wpa_cipher_valid_mgmt_group(int cipher)
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
@ -538,19 +555,30 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
return -1;
}
hdr = (const struct rsn_ie_hdr *) rsn_ie;
if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
rsn_ie[1] == rsn_ie_len - 2 &&
WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
pos = rsn_ie + 6;
left = rsn_ie_len - 6;
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;
data->proto = WPA_PROTO_OSEN;
} else {
const struct rsn_ie_hdr *hdr;
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);
}
pos = (const u8 *) (hdr + 1);
left = rsn_ie_len - sizeof(*hdr);
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_group(data->group_cipher)) {
@ -667,14 +695,10 @@ 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;
}
@ -709,11 +733,6 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
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);
@ -814,7 +833,7 @@ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_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 +
u8 buf[1 + SSID_MAX_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];
@ -828,7 +847,7 @@ void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
* 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)
if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return;
pos = buf;
*pos++ = ssid_len;
@ -1279,6 +1298,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
os_memmove(rpos + 2, rpos, end - rpos);
*rpos++ = 0;
*rpos++ = 0;
added += 2;
start[1] += 2;
rend = rpos;
} else {
/* Skip RSN Capabilities */
rpos += 2;
@ -1291,7 +1313,7 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
if (rpos == rend) {
/* No PMKID-Count field included; add it */
os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
os_memmove(rpos + 2 + PMKID_LEN, rpos, end + added - rpos);
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memcpy(rpos, pmkid, PMKID_LEN);
@ -1306,7 +1328,7 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
}
WPA_PUT_LE16(rpos, 1);
rpos += 2;
os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
os_memmove(rpos + PMKID_LEN, rpos, end + added - rpos);
os_memcpy(rpos, pmkid, PMKID_LEN);
added += PMKID_LEN;
start[1] += PMKID_LEN;
@ -1335,10 +1357,6 @@ int wpa_cipher_key_len(int cipher)
return 16;
case WPA_CIPHER_TKIP:
return 32;
case WPA_CIPHER_WEP104:
return 13;
case WPA_CIPHER_WEP40:
return 5;
}
return 0;
@ -1354,9 +1372,6 @@ int wpa_cipher_rsc_len(int cipher)
case WPA_CIPHER_GCMP:
case WPA_CIPHER_TKIP:
return 6;
case WPA_CIPHER_WEP104:
case WPA_CIPHER_WEP40:
return 0;
}
return 0;
@ -1376,9 +1391,6 @@ int wpa_cipher_to_alg(int cipher)
return WPA_ALG_GCMP;
case WPA_CIPHER_TKIP:
return WPA_ALG_TKIP;
case WPA_CIPHER_WEP104:
case WPA_CIPHER_WEP40:
return WPA_ALG_WEP;
case WPA_CIPHER_AES_128_CMAC:
return WPA_ALG_IGTK;
case WPA_CIPHER_BIP_GMAC_128:
@ -1416,12 +1428,6 @@ u32 wpa_cipher_to_suite(int proto, int cipher)
if (cipher & WPA_CIPHER_TKIP)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
if (cipher & WPA_CIPHER_WEP104)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
if (cipher & WPA_CIPHER_WEP40)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
if (cipher & WPA_CIPHER_NONE)
return (proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
@ -1525,10 +1531,6 @@ int wpa_pick_group_cipher(int ciphers)
return WPA_CIPHER_GTK_NOT_USED;
if (ciphers & WPA_CIPHER_TKIP)
return WPA_CIPHER_TKIP;
if (ciphers & WPA_CIPHER_WEP104)
return WPA_CIPHER_WEP104;
if (ciphers & WPA_CIPHER_WEP40)
return WPA_CIPHER_WEP40;
return -1;
}
@ -1626,20 +1628,6 @@ int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim)
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_WEP104) {
ret = os_snprintf(pos, end - pos, "%sWEP104",
pos == start ? "" : delim);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_WEP40) {
ret = os_snprintf(pos, end - pos, "%sWEP40",
pos == start ? "" : delim);
if (os_snprintf_error(end - pos, ret))
return -1;
pos += ret;
}
if (ciphers & WPA_CIPHER_NONE) {
ret = os_snprintf(pos, end - pos, "%sNONE",
pos == start ? "" : delim);

View File

@ -9,8 +9,6 @@
#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
@ -24,8 +22,8 @@
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256)
#define WPA_ALLOWED_GROUP_CIPHERS \
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | \
WPA_CIPHER_WEP40 | WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_GCMP_256 | WPA_CIPHER_CCMP_256 | \
WPA_CIPHER_GTK_NOT_USED)
#define WPA_SELECTOR_LEN 4
@ -42,13 +40,8 @@ WPA_CIPHER_GTK_NOT_USED)
#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
#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)
@ -70,13 +63,11 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
#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)
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
@ -308,7 +299,6 @@ struct wpa_igtk_kde {
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
@ -336,7 +326,6 @@ struct rsn_rdie {
le16 status_code;
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211R */
#ifdef _MSC_VER
#pragma pack(pop)
@ -446,6 +435,7 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
int wpa_cipher_to_alg(int cipher);
int wpa_cipher_valid_group(int cipher);
int wpa_cipher_valid_pairwise(int cipher);
int wpa_cipher_valid_mgmt_group(int cipher);
u32 wpa_cipher_to_suite(int proto, int cipher);

View File

@ -21,6 +21,7 @@
#ifdef ANDROID
#include <dirent.h>
#include <sys/stat.h>
#include <cutils/sockets.h>
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
@ -83,6 +84,13 @@ struct wpa_ctrl {
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
return wpa_ctrl_open2(ctrl_path, NULL);
}
struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path,
const char *cli_path)
{
struct wpa_ctrl *ctrl;
static int counter = 0;
@ -107,10 +115,18 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
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 (cli_path && cli_path[0] == '/') {
ret = os_snprintf(ctrl->local.sun_path,
sizeof(ctrl->local.sun_path),
"%s/" CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
cli_path, (int) getpid(), counter);
} else {
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 (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
close(ctrl->s);
os_free(ctrl);
@ -136,6 +152,8 @@ try_again:
#ifdef ANDROID
chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
/* Set group even if we do not have privileges to change owner */
chown(ctrl->local.sun_path, -1, AID_WIFI);
chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
if (os_strncmp(ctrl_path, "@android:", 9) == 0) {

View File

@ -28,6 +28,8 @@ extern "C" {
#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
/** Association rejected during connection attempt */
#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
/** Authentication rejected during connection attempt */
#define WPA_EVENT_AUTH_REJECT "CTRL-EVENT-AUTH-REJECT "
/** wpa_supplicant is exiting */
#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
/** Password change was completed successfully */
@ -68,6 +70,8 @@ extern "C" {
#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 "
/** No suitable network was found */
#define WPA_EVENT_NETWORK_NOT_FOUND "CTRL-EVENT-NETWORK-NOT-FOUND "
/** Change in the signal level was reported by the driver */
#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
/** Regulatory domain channel */
@ -227,6 +231,7 @@ extern "C" {
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
@ -276,6 +281,7 @@ extern "C" {
#define WPA_BSS_MASK_MESH_SCAN BIT(18)
#define WPA_BSS_MASK_SNR BIT(19)
#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
#define WPA_BSS_MASK_FST BIT(21)
/* VENDOR_ELEM_* frame id values */
@ -312,6 +318,20 @@ enum wpa_vendor_elem_frame {
*/
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
/**
* wpa_ctrl_open2 - Open a control interface to wpa_supplicant/hostapd
* @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
* @cli_path: Path for client UNIX domain sockets; ignored if UDP socket
* is 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
* when the socket path for client need to be specified explicitly. Default
* ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd and client
* socket path is /tmp.
*/
struct wpa_ctrl * wpa_ctrl_open2(const char *ctrl_path, const char *cli_path);
/**
* wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd

View File

@ -613,6 +613,15 @@ int crypto_bignum_is_zero(const struct crypto_bignum *a);
*/
int crypto_bignum_is_one(const struct crypto_bignum *a);
/**
* crypto_bignum_legendre - Compute the Legendre symbol (a/p)
* @a: Bignum
* @p: Bignum
* Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure
*/
int crypto_bignum_legendre(const struct crypto_bignum *a,
const struct crypto_bignum *p);
/**
* struct crypto_ec - Elliptic curve context
*
@ -757,6 +766,16 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
struct crypto_ec_point *p,
const struct crypto_bignum *x, int y_bit);
/**
* crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b
* @e: EC context from crypto_ec_init()
* @x: x coordinate
* Returns: y^2 on success, %NULL failure
*/
struct crypto_bignum *
crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
const struct crypto_bignum *x);
/**
* crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
* @e: EC context from crypto_ec_init()
@ -776,4 +795,15 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
const struct crypto_ec_point *p);
/**
* crypto_ec_point_cmp - Compare two EC points
* @e: EC context from crypto_ec_init()
* @a: EC point
* @b: EC point
* Returns: 0 on equal, non-zero otherwise
*/
int crypto_ec_point_cmp(const struct crypto_ec *e,
const struct crypto_ec_point *a,
const struct crypto_ec_point *b);
#endif /* CRYPTO_H */

View File

@ -1,783 +0,0 @@
/*
* Crypto wrapper for Microsoft CryptoAPI
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README 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

@ -161,7 +161,7 @@ struct omac1_test_vector {
u8 tag[16];
};
static struct omac1_test_vector omac1_test_vectors[] =
static const struct omac1_test_vector omac1_test_vectors[] =
{
{
{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
@ -210,7 +210,8 @@ static struct omac1_test_vector omac1_test_vectors[] =
};
static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
static int test_omac1_vector(const struct omac1_test_vector *tv,
unsigned int i)
{
u8 key[] = {
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
@ -515,6 +516,7 @@ static int test_key_wrap(void)
0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
};
#ifndef CONFIG_BORINGSSL
/* RFC 3394 - Test vector 4.2 */
u8 kek42[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@ -530,6 +532,7 @@ static int test_key_wrap(void)
0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
};
#endif /* CONFIG_BORINGSSL */
/* RFC 3394 - Test vector 4.3 */
u8 kek43[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@ -546,6 +549,7 @@ static int test_key_wrap(void)
0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
};
#ifndef CONFIG_BORINGSSL
/* RFC 3394 - Test vector 4.4 */
u8 kek44[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@ -563,6 +567,7 @@ static int test_key_wrap(void)
0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
};
#endif /* CONFIG_BORINGSSL */
/* RFC 3394 - Test vector 4.5 */
u8 kek45[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@ -623,6 +628,7 @@ static int test_key_wrap(void)
ret++;
}
#ifndef CONFIG_BORINGSSL
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
result)) {
@ -642,6 +648,7 @@ static int test_key_wrap(void)
wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
ret++;
}
#endif /* CONFIG_BORINGSSL */
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
@ -663,6 +670,7 @@ static int test_key_wrap(void)
ret++;
}
#ifndef CONFIG_BORINGSSL
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
result)) {
@ -682,6 +690,7 @@ static int test_key_wrap(void)
wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
ret++;
}
#endif /* CONFIG_BORINGSSL */
wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
@ -732,6 +741,7 @@ static int test_key_wrap(void)
static int test_md5(void)
{
#ifndef CONFIG_FIPS
struct {
char *data;
char *hash;
@ -810,6 +820,10 @@ static int test_md5(void)
wpa_printf(MSG_INFO, "MD5 test cases passed");
return errors;
#else /* CONFIG_FIPS */
wpa_printf(MSG_INFO, "MD5 test cases skipped due to CONFIG_FIPS");
return 0;
#endif /* CONFIG_FIPS */
}
@ -841,6 +855,7 @@ static int test_eap_fast(void)
0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
};
#ifndef CONFIG_FIPS
const u8 key_block[] = {
0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
@ -857,6 +872,7 @@ static int test_eap_fast(void)
0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
};
#endif /* CONFIG_FIPS */
const u8 sks[] = {
0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
@ -931,6 +947,7 @@ static int test_eap_fast(void)
errors++;
}
#ifndef CONFIG_FIPS
wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
"key expansion", seed, sizeof(seed),
@ -939,6 +956,7 @@ static int test_eap_fast(void)
wpa_printf(MSG_INFO, "PRF test - FAILED!");
errors++;
}
#endif /* CONFIG_FIPS */
wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
@ -983,14 +1001,14 @@ static int test_eap_fast(void)
}
static u8 key0[] =
static const u8 key0[] =
{
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b
};
static u8 data0[] = "Hi There";
static u8 prf0[] =
static const u8 data0[] = "Hi There";
static const u8 prf0[] =
{
0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
@ -1002,9 +1020,9 @@ static u8 prf0[] =
0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
};
static u8 key1[] = "Jefe";
static u8 data1[] = "what do ya want for nothing?";
static u8 prf1[] =
static const u8 key1[] = "Jefe";
static const u8 data1[] = "what do ya want for nothing?";
static const u8 prf1[] =
{
0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
@ -1017,13 +1035,13 @@ static u8 prf1[] =
};
static u8 key2[] =
static const u8 key2[] =
{
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa
};
static u8 data2[] =
static const u8 data2[] =
{
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
@ -1033,7 +1051,7 @@ static u8 data2[] =
0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
0xdd, 0xdd
};
static u8 prf2[] =
static const u8 prf2[] =
{
0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
@ -1052,7 +1070,7 @@ struct passphrase_test {
char psk[32];
};
static struct passphrase_test passphrase_tests[] =
static const struct passphrase_test passphrase_tests[] =
{
{
"password",
@ -1097,7 +1115,7 @@ struct rfc6070_test {
size_t dk_len;
};
static struct rfc6070_test rfc6070_tests[] =
static const struct rfc6070_test rfc6070_tests[] =
{
{
"password",
@ -1214,7 +1232,7 @@ static int test_sha1(void)
wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
u8 psk[32];
struct passphrase_test *test = &passphrase_tests[i];
const struct passphrase_test *test = &passphrase_tests[i];
if (pbkdf2_sha1(test->passphrase,
(const u8 *) test->ssid, strlen(test->ssid),
@ -1230,7 +1248,7 @@ static int test_sha1(void)
wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
for (i = 0; i < NUM_RFC6070_TESTS; i++) {
u8 dk[25];
struct rfc6070_test *test = &rfc6070_tests[i];
const struct rfc6070_test *test = &rfc6070_tests[i];
if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
test->c, dk, test->dk_len) == 0 &&
@ -1248,7 +1266,7 @@ static int test_sha1(void)
}
struct {
const struct {
char *data;
u8 hash[32];
} tests[] = {
@ -1272,7 +1290,7 @@ struct {
}
};
struct hmac_test {
const struct hmac_test {
u8 key[80];
size_t key_len;
u8 data[128];
@ -1513,7 +1531,7 @@ static int test_sha256(void)
}
for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
struct hmac_test *t = &hmac_tests[i];
const struct hmac_test *t = &hmac_tests[i];
wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
@ -1563,6 +1581,7 @@ static int test_sha256(void)
static int test_ms_funcs(void)
{
#ifndef CONFIG_FIPS
/* Test vector from RFC2759 example */
char *username = "User";
char *password = "clientPass";
@ -1655,6 +1674,10 @@ static int test_ms_funcs(void)
wpa_printf(MSG_INFO, "ms_funcs test cases passed");
return errors;
#else /* CONFIG_FIPS */
wpa_printf(MSG_INFO, "ms_funcs test cases skipped due to CONFIG_FIPS");
return 0;
#endif /* CONFIG_FIPS */
}

View File

@ -93,10 +93,12 @@ static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
}
#ifndef CONFIG_FIPS
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
}
#endif /* CONFIG_FIPS */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
@ -120,6 +122,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
#ifndef CONFIG_NO_RC4
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len)
{
@ -155,12 +158,15 @@ out:
return res;
#endif /* OPENSSL_NO_RC4 */
}
#endif /* CONFIG_NO_RC4 */
#ifndef CONFIG_FIPS
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
}
#endif /* CONFIG_FIPS */
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
@ -297,6 +303,9 @@ void aes_decrypt_deinit(void *ctx)
}
#ifndef CONFIG_FIPS
#ifndef CONFIG_OPENSSL_INTERNAL_AES_WRAP
int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
{
AES_KEY actx;
@ -323,6 +332,59 @@ int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
return res <= 0 ? -1 : 0;
}
#endif /* CONFIG_OPENSSL_INTERNAL_AES_WRAP */
#endif /* CONFIG_FIPS */
int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
EVP_CIPHER_CTX ctx;
int clen, len;
u8 buf[16];
EVP_CIPHER_CTX_init(&ctx);
if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
return -1;
EVP_CIPHER_CTX_set_padding(&ctx, 0);
clen = data_len;
if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
clen != (int) data_len)
return -1;
len = sizeof(buf);
if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
return -1;
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
EVP_CIPHER_CTX ctx;
int plen, len;
u8 buf[16];
EVP_CIPHER_CTX_init(&ctx);
if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
return -1;
EVP_CIPHER_CTX_set_padding(&ctx, 0);
plen = data_len;
if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
plen != (int) data_len)
return -1;
len = sizeof(buf);
if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
return -1;
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
int crypto_mod_exp(const u8 *base, size_t base_len,
const u8 *power, size_t power_len,
@ -380,11 +442,13 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
return NULL;
switch (alg) {
#ifndef CONFIG_NO_RC4
#ifndef OPENSSL_NO_RC4
case CRYPTO_CIPHER_ALG_RC4:
cipher = EVP_rc4();
break;
#endif /* OPENSSL_NO_RC4 */
#endif /* CONFIG_NO_RC4 */
#ifndef OPENSSL_NO_AES
case CRYPTO_CIPHER_ALG_AES:
switch (key_len) {
@ -1057,6 +1121,42 @@ int crypto_bignum_is_one(const struct crypto_bignum *a)
}
int crypto_bignum_legendre(const struct crypto_bignum *a,
const struct crypto_bignum *p)
{
BN_CTX *bnctx;
BIGNUM *exp = NULL, *tmp = NULL;
int res = -2;
bnctx = BN_CTX_new();
if (bnctx == NULL)
return -2;
exp = BN_new();
tmp = BN_new();
if (!exp || !tmp ||
/* exp = (p-1) / 2 */
!BN_sub(exp, (const BIGNUM *) p, BN_value_one()) ||
!BN_rshift1(exp, exp) ||
!BN_mod_exp(tmp, (const BIGNUM *) a, exp, (const BIGNUM *) p,
bnctx))
goto fail;
if (BN_is_word(tmp, 1))
res = 1;
else if (BN_is_zero(tmp))
res = 0;
else
res = -1;
fail:
BN_clear_free(tmp);
BN_clear_free(exp);
BN_CTX_free(bnctx);
return res;
}
#ifdef CONFIG_ECC
struct crypto_ec {
@ -1064,6 +1164,8 @@ struct crypto_ec {
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
BIGNUM *a;
BIGNUM *b;
};
struct crypto_ec * crypto_ec_init(int group)
@ -1088,6 +1190,26 @@ struct crypto_ec * crypto_ec_init(int group)
case 26:
nid = NID_secp224r1;
break;
#ifdef NID_brainpoolP224r1
case 27:
nid = NID_brainpoolP224r1;
break;
#endif /* NID_brainpoolP224r1 */
#ifdef NID_brainpoolP256r1
case 28:
nid = NID_brainpoolP256r1;
break;
#endif /* NID_brainpoolP256r1 */
#ifdef NID_brainpoolP384r1
case 29:
nid = NID_brainpoolP384r1;
break;
#endif /* NID_brainpoolP384r1 */
#ifdef NID_brainpoolP512r1
case 30:
nid = NID_brainpoolP512r1;
break;
#endif /* NID_brainpoolP512r1 */
default:
return NULL;
}
@ -1100,9 +1222,11 @@ struct crypto_ec * crypto_ec_init(int group)
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
e->order = BN_new();
e->a = BN_new();
e->b = BN_new();
if (e->group == NULL || e->bnctx == NULL || e->prime == NULL ||
e->order == NULL ||
!EC_GROUP_get_curve_GFp(e->group, e->prime, NULL, NULL, e->bnctx) ||
e->order == NULL || e->a == NULL || e->b == NULL ||
!EC_GROUP_get_curve_GFp(e->group, e->prime, e->a, e->b, e->bnctx) ||
!EC_GROUP_get_order(e->group, e->order, e->bnctx)) {
crypto_ec_deinit(e);
e = NULL;
@ -1116,6 +1240,8 @@ void crypto_ec_deinit(struct crypto_ec *e)
{
if (e == NULL)
return;
BN_clear_free(e->b);
BN_clear_free(e->a);
BN_clear_free(e->order);
BN_clear_free(e->prime);
EC_GROUP_free(e->group);
@ -1263,6 +1389,33 @@ int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
}
struct crypto_bignum *
crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
const struct crypto_bignum *x)
{
BIGNUM *tmp, *tmp2, *y_sqr = NULL;
tmp = BN_new();
tmp2 = BN_new();
/* y^2 = x^3 + ax + b */
if (tmp && tmp2 &&
BN_mod_sqr(tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
BN_mod_mul(tmp, tmp, (const BIGNUM *) x, e->prime, e->bnctx) &&
BN_mod_mul(tmp2, e->a, (const BIGNUM *) x, e->prime, e->bnctx) &&
BN_mod_add_quick(tmp2, tmp2, tmp, e->prime) &&
BN_mod_add_quick(tmp2, tmp2, e->b, e->prime)) {
y_sqr = tmp2;
tmp2 = NULL;
}
BN_clear_free(tmp);
BN_clear_free(tmp2);
return (struct crypto_bignum *) y_sqr;
}
int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
const struct crypto_ec_point *p)
{
@ -1273,7 +1426,17 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
const struct crypto_ec_point *p)
{
return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p, e->bnctx);
return EC_POINT_is_on_curve(e->group, (const EC_POINT *) p,
e->bnctx) == 1;
}
int crypto_ec_point_cmp(const struct crypto_ec *e,
const struct crypto_ec_point *a,
const struct crypto_ec_point *b)
{
return EC_POINT_cmp(e->group, (const EC_POINT *) a,
(const EC_POINT *) b, e->bnctx);
}
#endif /* CONFIG_ECC */

View File

@ -1153,7 +1153,7 @@ dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime), \
dh_group ## id ## _order, sizeof(dh_group ## id ## _order), safe }
static struct dh_group dh_groups[] = {
static const struct dh_group dh_groups[] = {
DH_GROUP(5, 1),
#ifdef ALL_DH_GROUPS
DH_GROUP(1, 1),

View File

@ -13,13 +13,21 @@
#include "crypto.h"
static void sha1_transform(u8 *state, const u8 data[64])
static void sha1_transform(u32 *state, const u8 data[64])
{
SHA_CTX context;
os_memset(&context, 0, sizeof(context));
os_memcpy(&context.h0, state, 5 * 4);
context.h0 = state[0];
context.h1 = state[1];
context.h2 = state[2];
context.h3 = state[3];
context.h4 = state[4];
SHA1_Transform(&context, data);
os_memcpy(state, &context.h0, 5 * 4);
state[0] = context.h0;
state[1] = context.h1;
state[2] = context.h2;
state[3] = context.h3;
state[4] = context.h4;
}
@ -53,7 +61,7 @@ int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
/* w_i = G(t, XVAL) */
os_memcpy(_t, t, 20);
sha1_transform((u8 *) _t, xkey);
sha1_transform(_t, xkey);
_t[0] = host_to_be32(_t[0]);
_t[1] = host_to_be32(_t[1]);
_t[2] = host_to_be32(_t[2]);

View File

@ -78,9 +78,8 @@ static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
* @challenge: 8-octet Challenge (OUT)
* Returns: 0 on success, -1 on failure
*/
static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len,
u8 *challenge)
int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len, u8 *challenge)
{
u8 hash[SHA1_MAC_LEN];
const unsigned char *addr[3];
@ -175,9 +174,8 @@ int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
u8 password_hash[16];
if (challenge_hash(peer_challenge, auth_challenge, username,
username_len, challenge))
return -1;
if (nt_password_hash(password, password_len, password_hash))
username_len, challenge) ||
nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
return 0;
@ -257,12 +255,9 @@ int generate_authenticator_response_pwhash(
addr2[1] = challenge;
addr2[2] = magic2;
if (hash_nt_password_hash(password_hash, password_hash_hash))
return -1;
if (sha1_vector(3, addr1, len1, response))
return -1;
if (challenge_hash(peer_challenge, auth_challenge, username,
if (hash_nt_password_hash(password_hash, password_hash_hash) ||
sha1_vector(3, addr1, len1, response) ||
challenge_hash(peer_challenge, auth_challenge, username,
username_len, challenge))
return -1;
return sha1_vector(3, addr2, len2, response);
@ -417,6 +412,8 @@ int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
}
#ifndef CONFIG_NO_RC4
#define PWBLOCK_LEN 516
/**
@ -436,10 +433,8 @@ int encrypt_pw_block_with_password_hash(
os_memset(pw_block, 0, PWBLOCK_LEN);
if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
return -1;
if (ucs2_len > 256)
if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0
|| ucs2_len > 256)
return -1;
offset = (256 - ucs2_len) * 2;
@ -484,6 +479,8 @@ int new_password_encrypted_with_old_nt_password_hash(
return 0;
}
#endif /* CONFIG_NO_RC4 */
/**
* nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13

View File

@ -33,6 +33,8 @@ int nt_challenge_response(const u8 *challenge, const u8 *password,
void challenge_response(const u8 *challenge, const u8 *password_hash,
u8 *response);
int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
const u8 *username, size_t username_len, u8 *challenge);
int nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash);
int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);

View File

@ -181,6 +181,7 @@ int random_get_bytes(void *buf, size_t len)
#ifdef CONFIG_FIPS
/* Mix in additional entropy from the crypto module */
bytes = buf;
left = len;
while (left) {
size_t siz, i;

View File

@ -95,5 +95,10 @@ int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
SHA1_pos++;
}
os_memset(A_MD5, 0, MD5_MAC_LEN);
os_memset(P_MD5, 0, MD5_MAC_LEN);
os_memset(A_SHA1, 0, SHA1_MAC_LEN);
os_memset(P_SHA1, 0, SHA1_MAC_LEN);
return 0;
}

View File

@ -66,5 +66,7 @@ int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
len[0] = SHA1_MAC_LEN;
}
os_memset(hash, 0, SHA1_MAC_LEN);
return 0;
}

View File

@ -61,6 +61,7 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (iter == 255) {
os_memset(out, 0, outlen);
os_memset(T, 0, SHA256_MAC_LEN);
return -1;
}
iter++;
@ -68,9 +69,11 @@ int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
{
os_memset(out, 0, outlen);
os_memset(T, 0, SHA256_MAC_LEN);
return -1;
}
}
os_memset(T, 0, SHA256_MAC_LEN);
return 0;
}

View File

@ -0,0 +1,100 @@
/*
* SHA384-based KDF (IEEE 802.11ac)
* Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
#include "includes.h"
#include "common.h"
#include "sha384.h"
#include "crypto.h"
/**
* sha384_prf - SHA384-based Key derivation function (IEEE 802.11ac, 11.6.1.7.2)
* @key: Key for KDF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @data: Extra data to bind into the key
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bytes of key to generate
*
* This function is used to derive new, cryptographically separate keys from a
* given key.
*/
void sha384_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
sha384_prf_bits(key, key_len, label, data, data_len, buf, buf_len * 8);
}
/**
* sha384_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function
* @key: Key for KDF
* @key_len: Length of the key in bytes
* @label: A unique label for each purpose of the PRF
* @data: Extra data to bind into the key
* @data_len: Length of the data
* @buf: Buffer for the generated pseudo-random key
* @buf_len: Number of bits of key to generate
*
* This function is used to derive new, cryptographically separate keys from a
* given key. If the requested buf_len is not divisible by eight, the least
* significant 1-7 bits of the last octet in the output are not part of the
* requested output.
*/
void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits)
{
u16 counter = 1;
size_t pos, plen;
u8 hash[SHA384_MAC_LEN];
const u8 *addr[4];
size_t len[4];
u8 counter_le[2], length_le[2];
size_t buf_len = (buf_len_bits + 7) / 8;
addr[0] = counter_le;
len[0] = 2;
addr[1] = (u8 *) label;
len[1] = os_strlen(label);
addr[2] = data;
len[2] = data_len;
addr[3] = length_le;
len[3] = sizeof(length_le);
WPA_PUT_LE16(length_le, buf_len_bits);
pos = 0;
while (pos < buf_len) {
plen = buf_len - pos;
WPA_PUT_LE16(counter_le, counter);
if (plen >= SHA384_MAC_LEN) {
hmac_sha384_vector(key, key_len, 4, addr, len,
&buf[pos]);
pos += SHA384_MAC_LEN;
} else {
hmac_sha384_vector(key, key_len, 4, addr, len, hash);
os_memcpy(&buf[pos], hash, plen);
pos += plen;
break;
}
counter++;
}
/*
* Mask out unused bits in the last octet if it does not use all the
* bits.
*/
if (buf_len_bits % 8) {
u8 mask = 0xff << (8 - buf_len_bits % 8);
buf[pos - 1] &= mask;
}
os_memset(hash, 0, sizeof(hash));
}

View File

@ -15,5 +15,10 @@ int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
size_t data_len, u8 *mac);
void sha384_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
void sha384_prf_bits(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf,
size_t buf_len_bits);
#endif /* SHA384_H */

View File

@ -11,9 +11,7 @@
struct tls_connection;
struct tls_keys {
const u8 *master_key; /* TLS master secret */
size_t master_key_len;
struct tls_random {
const u8 *client_random;
size_t client_random_len;
const u8 *server_random;
@ -81,6 +79,7 @@ struct tls_config {
int fips_mode;
int cert_in_cb;
const char *openssl_ciphers;
unsigned int tls_session_lifetime;
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
@ -95,6 +94,7 @@ struct tls_config {
#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
#define TLS_CONN_EAP_FAST BIT(7)
#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
/**
* struct tls_connection_params - Parameters for TLS connection
@ -255,6 +255,7 @@ int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
enum {
TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
};
@ -265,10 +266,12 @@ enum {
* @conn: Connection context data from tls_connection_init()
* @params: Connection parameters
* Returns: 0 on success, -1 on failure,
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
* PKCS#11 engine failure, or
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
* failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
* PKCS#11 engine private key.
* PKCS#11 engine private key, or
* TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
* failure.
*/
int __must_check
tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
@ -279,10 +282,12 @@ tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
* @tls_ctx: TLS context data from tls_init()
* @params: Global TLS parameters
* Returns: 0 on success, -1 on failure,
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
* PKCS#11 engine failure, or
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
* failure, or
* TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
* PKCS#11 engine private key.
* PKCS#11 engine private key, or
* TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
* failure.
*/
int __must_check tls_global_set_params(
void *tls_ctx, const struct tls_connection_params *params);
@ -301,22 +306,28 @@ int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @verify_peer: 1 = verify peer certificate
* @flags: Connection flags (TLS_CONN_*)
* @session_ctx: Session caching context or %NULL to use default
* @session_ctx_len: Length of @session_ctx in bytes.
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_set_verify(void *tls_ctx,
struct tls_connection *conn,
int verify_peer);
int verify_peer,
unsigned int flags,
const u8 *session_ctx,
size_t session_ctx_len);
/**
* tls_connection_get_keys - Get master key and random data from TLS connection
* tls_connection_get_random - Get random data from TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @keys: Structure of key/random data (filled on success)
* @data: Structure of client/server random data (filled on success)
* Returns: 0 on success, -1 on failure
*/
int __must_check tls_connection_get_keys(void *tls_ctx,
int __must_check tls_connection_get_random(void *tls_ctx,
struct tls_connection *conn,
struct tls_keys *keys);
struct tls_random *data);
/**
* tls_connection_prf - Use TLS-PRF to derive keying material
@ -325,23 +336,22 @@ int __must_check tls_connection_get_keys(void *tls_ctx,
* @label: Label (e.g., description of the key) for PRF
* @server_random_first: seed is 0 = client_random|server_random,
* 1 = server_random|client_random
* @skip_keyblock: Skip TLS key block from the beginning of PRF output
* @out: Buffer for output data from TLS-PRF
* @out_len: Length of the output buffer
* Returns: 0 on success, -1 on failure
*
* This function is optional to implement if tls_connection_get_keys() provides
* access to master secret and server/client random values. If these values are
* not exported from the TLS library, tls_connection_prf() is required so that
* further keying material can be derived from the master secret. If not
* implemented, the function will still need to be defined, but it can just
* return -1. Example implementation of this function is in tls_prf_sha1_md5()
* when it is called with seed set to client_random|server_random (or
* server_random|client_random).
* tls_connection_prf() is required so that further keying material can be
* derived from the master secret. Example implementation of this function is in
* tls_prf_sha1_md5() when it is called with seed set to
* client_random|server_random (or server_random|client_random). For TLSv1.2 and
* newer, a different PRF is needed, though.
*/
int __must_check tls_connection_prf(void *tls_ctx,
struct tls_connection *conn,
const char *label,
int server_random_first,
int skip_keyblock,
u8 *out, size_t out_len);
/**
@ -460,6 +470,19 @@ int __must_check tls_connection_set_cipher_list(void *tls_ctx,
struct tls_connection *conn,
u8 *ciphers);
/**
* tls_get_version - Get the current TLS version number
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @buf: Buffer for returning the TLS version number
* @buflen: buf size
* Returns: 0 on success, -1 on failure
*
* Get the currently used TLS version number.
*/
int __must_check tls_get_version(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen);
/**
* tls_get_cipher - Get current cipher name
* @tls_ctx: TLS context data from tls_init()
@ -527,23 +550,6 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
int tls_connection_get_write_alerts(void *tls_ctx,
struct tls_connection *conn);
/**
* tls_connection_get_keyblock_size - Get TLS key_block size
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
* failure
*/
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn);
/**
* tls_capabilities - Get supported TLS capabilities
* @tls_ctx: TLS context data from tls_init()
* Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
*/
unsigned int tls_capabilities(void *tls_ctx);
typedef int (*tls_session_ticket_cb)
(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
const u8 *server_random, u8 *master_secret);
@ -569,4 +575,14 @@ void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
int tls_get_library_version(char *buf, size_t buf_len);
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data);
void tls_connection_set_success_data_resumed(struct tls_connection *conn);
const struct wpabuf *
tls_connection_get_success_data(struct tls_connection *conn);
void tls_connection_remove_session(struct tls_connection *conn);
#endif /* TLS_H */

View File

@ -708,7 +708,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
int verify_peer, unsigned int flags,
const u8 *session_ctx, size_t session_ctx_len)
{
if (conn == NULL || conn->session == NULL)
return -1;
@ -722,8 +723,8 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
struct tls_random *keys)
{
#if GNUTLS_VERSION_NUMBER >= 0x030012
gnutls_datum_t client, server;
@ -747,9 +748,9 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
int skip_keyblock, u8 *out, size_t out_len)
{
if (conn == NULL || conn->session == NULL)
if (conn == NULL || conn->session == NULL || skip_keyblock)
return -1;
return gnutls_prf(conn->session, os_strlen(label), label,
@ -1426,6 +1427,14 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
/* TODO */
return -1;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@ -1476,20 +1485,6 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
/* TODO */
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb, void *ctx)
@ -1503,3 +1498,26 @@ int tls_get_library_version(char *buf, size_t buf_len)
return os_snprintf(buf, buf_len, "GnuTLS build=%s run=%s",
GNUTLS_VERSION, gnutls_check_version(NULL));
}
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
}
void tls_connection_set_success_data_resumed(struct tls_connection *conn)
{
}
const struct wpabuf *
tls_connection_get_success_data(struct tls_connection *conn)
{
return NULL;
}
void tls_connection_remove_session(struct tls_connection *conn)
{
}

View File

@ -192,26 +192,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (params->subject_match) {
wpa_printf(MSG_INFO, "TLS: subject_match not supported");
tlsv1_cred_free(cred);
return -1;
}
if (params->altsubject_match) {
wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
tlsv1_cred_free(cred);
return -1;
}
if (params->suffix_match) {
wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
tlsv1_cred_free(cred);
return -1;
}
if (params->domain_match) {
wpa_printf(MSG_INFO, "TLS: domain_match not supported");
tlsv1_cred_free(cred);
return -1;
}
if (params->openssl_ciphers) {
wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
wpa_printf(MSG_INFO, "TLS: openssl_ciphers not supported");
tlsv1_cred_free(cred);
return -1;
}
@ -323,7 +328,8 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer)
int verify_peer, unsigned int flags,
const u8 *session_ctx, size_t session_ctx_len)
{
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
@ -333,16 +339,30 @@ int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
}
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
struct tls_random *data)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_get_keys(conn->client, keys);
return tlsv1_client_get_random(conn->client, data);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_get_keys(conn->server, keys);
return tlsv1_server_get_random(conn->server, data);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
static int tls_get_keyblock_size(struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_get_keyblock_size(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_get_keyblock_size(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
@ -350,23 +370,41 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
int skip_keyblock, u8 *out, size_t out_len)
{
int ret = -1, skip = 0;
u8 *tmp_out = NULL;
u8 *_out = out;
if (skip_keyblock) {
skip = tls_get_keyblock_size(conn);
if (skip < 0)
return -1;
tmp_out = os_malloc(skip + out_len);
if (!tmp_out)
return -1;
_out = tmp_out;
}
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client) {
return tlsv1_client_prf(conn->client, label,
server_random_first,
out, out_len);
ret = tlsv1_client_prf(conn->client, label,
server_random_first,
_out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server) {
return tlsv1_server_prf(conn->server, label,
server_random_first,
out, out_len);
ret = tlsv1_server_prf(conn->server, label,
server_random_first,
_out, out_len);
}
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
if (ret == 0 && skip_keyblock)
os_memcpy(out, _out + skip, out_len);
bin_clear_free(tmp_out, skip);
return ret;
}
@ -580,6 +618,14 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
/* TODO */
return -1;
}
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@ -637,27 +683,6 @@ int tls_connection_get_write_alerts(void *tls_ctx,
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
#ifdef CONFIG_TLS_INTERNAL_CLIENT
if (conn->client)
return tlsv1_client_get_keyblock_size(conn->client);
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
#ifdef CONFIG_TLS_INTERNAL_SERVER
if (conn->server)
return tlsv1_server_get_keyblock_size(conn->server);
#endif /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
int tls_connection_set_session_ticket_cb(void *tls_ctx,
struct tls_connection *conn,
tls_session_ticket_cb cb,
@ -683,3 +708,26 @@ int tls_get_library_version(char *buf, size_t buf_len)
{
return os_snprintf(buf, buf_len, "internal");
}
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
}
void tls_connection_set_success_data_resumed(struct tls_connection *conn)
{
}
const struct wpabuf *
tls_connection_get_success_data(struct tls_connection *conn)
{
return NULL;
}
void tls_connection_remove_session(struct tls_connection *conn)
{
}

View File

@ -72,14 +72,15 @@ int tls_global_set_verify(void *tls_ctx, int check_crl)
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer)
int verify_peer, unsigned int flags,
const u8 *session_ctx, size_t session_ctx_len)
{
return -1;
}
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys)
int tls_connection_get_random(void *tls_ctx, struct tls_connection *conn,
struct tls_random *data)
{
return -1;
}
@ -87,7 +88,7 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
int skip_keyblock, u8 *out, size_t out_len)
{
return -1;
}
@ -140,6 +141,13 @@ int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
}
int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
return -1;
}
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
@ -181,20 +189,30 @@ int tls_connection_get_write_alerts(void *tls_ctx,
}
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
return -1;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
int tls_get_library_version(char *buf, size_t buf_len)
{
return os_snprintf(buf, buf_len, "none");
}
void tls_connection_set_success_data(struct tls_connection *conn,
struct wpabuf *data)
{
}
void tls_connection_set_success_data_resumed(struct tls_connection *conn)
{
}
const struct wpabuf *
tls_connection_get_success_data(struct tls_connection *conn)
{
return NULL;
}
void tls_connection_remove_session(struct tls_connection *conn)
{
}

File diff suppressed because it is too large Load Diff

View File

@ -1,763 +0,0 @@
/*
* SSL/TLS interface functions for Microsoft Schannel
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/
/*
* FIX: Go through all SSPI functions and verify what needs to be freed
* FIX: session resumption
* TODO: add support for server cert chain validation
* TODO: add support for CA cert validation
* TODO: add support for EAP-TLS (client cert/key conf)
*/
#include "includes.h"
#include <windows.h>
#include <wincrypt.h>
#include <schannel.h>
#define SECURITY_WIN32
#include <security.h>
#include <sspi.h>
#include "common.h"
#include "tls.h"
struct tls_global {
HMODULE hsecurity;
PSecurityFunctionTable sspi;
HCERTSTORE my_cert_store;
};
struct tls_connection {
int established, start;
int failed, read_alerts, write_alerts;
SCHANNEL_CRED schannel_cred;
CredHandle creds;
CtxtHandle context;
u8 eap_tls_prf[128];
int eap_tls_prf_set;
};
static int schannel_load_lib(struct tls_global *global)
{
INIT_SECURITY_INTERFACE pInitSecurityInterface;
global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
if (global->hsecurity == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
global->hsecurity, "InitSecurityInterfaceA");
if (pInitSecurityInterface == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not find "
"InitSecurityInterfaceA from Secur32.dll",
__func__);
FreeLibrary(global->hsecurity);
global->hsecurity = NULL;
return -1;
}
global->sspi = pInitSecurityInterface();
if (global->sspi == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not read security "
"interface - 0x%x",
__func__, (unsigned int) GetLastError());
FreeLibrary(global->hsecurity);
global->hsecurity = NULL;
return -1;
}
return 0;
}
void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
if (schannel_load_lib(global)) {
os_free(global);
return NULL;
}
return global;
}
void tls_deinit(void *ssl_ctx)
{
struct tls_global *global = ssl_ctx;
if (global->my_cert_store)
CertCloseStore(global->my_cert_store, 0);
FreeLibrary(global->hsecurity);
os_free(global);
}
int tls_get_errors(void *ssl_ctx)
{
return 0;
}
struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_connection *conn;
conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
conn->start = 1;
return conn;
}
void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
os_free(conn);
}
int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
{
return conn ? conn->established : 0;
}
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
struct tls_global *global = ssl_ctx;
if (conn == NULL)
return -1;
conn->eap_tls_prf_set = 0;
conn->established = conn->failed = 0;
conn->read_alerts = conn->write_alerts = 0;
global->sspi->DeleteSecurityContext(&conn->context);
/* FIX: what else needs to be reseted? */
return 0;
}
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
return -1;
}
int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
return -1;
}
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
return -1;
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
/* Schannel does not export master secret or client/server random. */
return -1;
}
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
/*
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
* EAP-TTLS cannot use this, though, since they are using different
* labels. The only option could be to implement TLSv1 completely here
* and just use Schannel or CryptoAPI for low-level crypto
* functionality..
*/
if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
os_strcmp(label, "client EAP encryption") != 0 ||
out_len > sizeof(conn->eap_tls_prf))
return -1;
os_memcpy(out, conn->eap_tls_prf, out_len);
return 0;
}
static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
struct tls_connection *conn)
{
DWORD sspi_flags, sspi_flags_out;
SecBufferDesc outbuf;
SecBuffer outbufs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
sspi_flags = ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_MANUAL_CRED_VALIDATION;
wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
outbufs[0].pvBuffer = NULL;
outbufs[0].BufferType = SECBUFFER_TOKEN;
outbufs[0].cbBuffer = 0;
outbuf.cBuffers = 1;
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
#ifdef UNICODE
status = global->sspi->InitializeSecurityContextW(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
if (status != SEC_I_CONTINUE_NEEDED) {
wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
"failed - 0x%x",
__func__, (unsigned int) status);
return NULL;
}
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
struct wpabuf *buf;
wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
conn->start = 0;
buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
outbufs[0].cbBuffer);
if (buf == NULL)
return NULL;
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
return buf;
}
wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
return NULL;
}
#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
typedef struct _SecPkgContext_EapKeyBlock {
BYTE rgbKeys[128];
BYTE rgbIVs[64];
} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
{
SECURITY_STATUS status;
SecPkgContext_EapKeyBlock kb;
/* Note: Windows NT and Windows Me/98/95 do not support getting
* EapKeyBlock */
status = global->sspi->QueryContextAttributes(
&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
"SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
__func__, (int) status);
return -1;
}
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
kb.rgbKeys, sizeof(kb.rgbKeys));
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
kb.rgbIVs, sizeof(kb.rgbIVs));
os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
conn->eap_tls_prf_set = 1;
return 0;
}
struct wpabuf * tls_connection_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
struct tls_global *global = tls_ctx;
DWORD sspi_flags, sspi_flags_out;
SecBufferDesc inbuf, outbuf;
SecBuffer inbufs[2], outbufs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
struct wpabuf *out_buf = NULL;
if (appl_data)
*appl_data = NULL;
if (conn->start)
return tls_conn_hs_clienthello(global, conn);
wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
(int) wpabuf_len(in_data));
sspi_flags = ISC_REQ_REPLAY_DETECT |
ISC_REQ_CONFIDENTIALITY |
ISC_RET_EXTENDED_ERROR |
ISC_REQ_ALLOCATE_MEMORY |
ISC_REQ_MANUAL_CRED_VALIDATION;
/* Input buffer for Schannel */
inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
inbufs[0].cbBuffer = wpabuf_len(in_data);
inbufs[0].BufferType = SECBUFFER_TOKEN;
/* Place for leftover data from Schannel */
inbufs[1].pvBuffer = NULL;
inbufs[1].cbBuffer = 0;
inbufs[1].BufferType = SECBUFFER_EMPTY;
inbuf.cBuffers = 2;
inbuf.pBuffers = inbufs;
inbuf.ulVersion = SECBUFFER_VERSION;
/* Output buffer for Schannel */
outbufs[0].pvBuffer = NULL;
outbufs[0].cbBuffer = 0;
outbufs[0].BufferType = SECBUFFER_TOKEN;
outbuf.cBuffers = 1;
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
#ifdef UNICODE
status = global->sspi->InitializeSecurityContextW(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
#endif /* UNICODE */
wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
"status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
"intype[1]=%d outlen[0]=%d",
(int) status, (int) inbufs[0].cbBuffer,
(int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
(int) inbufs[1].BufferType,
(int) outbufs[0].cbBuffer);
if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
(FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
outbufs[0].cbBuffer);
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
outbufs[0].pvBuffer = NULL;
if (out_buf == NULL)
return NULL;
}
}
switch (status) {
case SEC_E_INCOMPLETE_MESSAGE:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
break;
case SEC_I_CONTINUE_NEEDED:
wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
break;
case SEC_E_OK:
/* TODO: verify server certificate chain */
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
"completed successfully");
conn->established = 1;
tls_get_eap(global, conn);
/* Need to return something to get final TLS ACK. */
if (out_buf == NULL)
out_buf = wpabuf_alloc(0);
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
"application data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
if (appl_data) {
*appl_data = wpabuf_alloc_copy(
outbufs[1].pvBuffer,
outbufs[1].cbBuffer);
}
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
break;
case SEC_I_INCOMPLETE_CREDENTIALS:
wpa_printf(MSG_DEBUG,
"Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
break;
case SEC_E_WRONG_PRINCIPAL:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
break;
case SEC_E_INTERNAL_ERROR:
wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
break;
}
if (FAILED(status)) {
wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
"(out_buf=%p)", out_buf);
conn->failed++;
global->sspi->DeleteSecurityContext(&conn->context);
return out_buf;
}
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
/* TODO: Can this happen? What to do with this data? */
wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
return out_buf;
}
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data,
struct wpabuf **appl_data)
{
return NULL;
}
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
struct tls_global *global = tls_ctx;
SECURITY_STATUS status;
SecBufferDesc buf;
SecBuffer bufs[4];
SecPkgContext_StreamSizes sizes;
int i;
struct wpabuf *out;
status = global->sspi->QueryContextAttributes(&conn->context,
SECPKG_ATTR_STREAM_SIZES,
&sizes);
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
__func__);
return NULL;
}
wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
__func__,
(unsigned int) sizes.cbHeader,
(unsigned int) sizes.cbTrailer);
out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
sizes.cbTrailer);
os_memset(&bufs, 0, sizeof(bufs));
bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
bufs[0].cbBuffer = sizes.cbHeader;
bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
bufs[1].pvBuffer = wpabuf_put(out, 0);
wpabuf_put_buf(out, in_data);
bufs[1].cbBuffer = wpabuf_len(in_data);
bufs[1].BufferType = SECBUFFER_DATA;
bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
bufs[2].cbBuffer = sizes.cbTrailer;
bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
buf.ulVersion = SECBUFFER_VERSION;
buf.cBuffers = 3;
buf.pBuffers = bufs;
status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
"len[2]=%d type[2]=%d",
(int) status,
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
"out_data=%p bufs %p %p %p",
wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
bufs[2].pvBuffer);
for (i = 0; i < 3; i++) {
if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
{
wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
bufs[i].pvBuffer, bufs[i].cbBuffer);
}
}
if (status == SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
"from EncryptMessage", out);
return out;
}
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
__func__, (int) status);
wpabuf_free(out);
return NULL;
}
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
struct tls_connection *conn,
const struct wpabuf *in_data)
{
struct tls_global *global = tls_ctx;
SECURITY_STATUS status;
SecBufferDesc buf;
SecBuffer bufs[4];
int i;
struct wpabuf *out, *tmp;
wpa_hexdump_buf(MSG_MSGDUMP,
"Schannel: Encrypted data to DecryptMessage", in_data);
os_memset(&bufs, 0, sizeof(bufs));
tmp = wpabuf_dup(in_data);
if (tmp == NULL)
return NULL;
bufs[0].pvBuffer = wpabuf_mhead(tmp);
bufs[0].cbBuffer = wpabuf_len(in_data);
bufs[0].BufferType = SECBUFFER_DATA;
bufs[1].BufferType = SECBUFFER_EMPTY;
bufs[2].BufferType = SECBUFFER_EMPTY;
bufs[3].BufferType = SECBUFFER_EMPTY;
buf.ulVersion = SECBUFFER_VERSION;
buf.cBuffers = 4;
buf.pBuffers = bufs;
status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
NULL);
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
"status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
"len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
(int) status,
(int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
(int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
(int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
(int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
"out_data=%p bufs %p %p %p %p",
wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
bufs[2].pvBuffer, bufs[3].pvBuffer);
switch (status) {
case SEC_E_INCOMPLETE_MESSAGE:
wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
__func__);
break;
case SEC_E_OK:
wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
for (i = 0; i < 4; i++) {
if (bufs[i].BufferType == SECBUFFER_DATA)
break;
}
if (i == 4) {
wpa_printf(MSG_DEBUG, "%s: No output data from "
"DecryptMessage", __func__);
wpabuf_free(tmp);
return NULL;
}
wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
"DecryptMessage",
bufs[i].pvBuffer, bufs[i].cbBuffer);
out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
wpabuf_free(tmp);
return out;
}
wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
__func__, (int) status);
wpabuf_free(tmp);
return NULL;
}
int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
{
return 0;
}
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
u8 *ciphers)
{
return -1;
}
int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
char *buf, size_t buflen)
{
return -1;
}
int tls_connection_enable_workaround(void *ssl_ctx,
struct tls_connection *conn)
{
return 0;
}
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
return -1;
}
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->failed;
}
int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->read_alerts;
}
int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return -1;
return conn->write_alerts;
}
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params)
{
struct tls_global *global = tls_ctx;
ALG_ID algs[1];
SECURITY_STATUS status;
TimeStamp ts_expiry;
if (conn == NULL)
return -1;
if (params->subject_match) {
wpa_printf(MSG_INFO, "TLS: subject_match not supported");
return -1;
}
if (params->altsubject_match) {
wpa_printf(MSG_INFO, "TLS: altsubject_match not supported");
return -1;
}
if (params->suffix_match) {
wpa_printf(MSG_INFO, "TLS: suffix_match not supported");
return -1;
}
if (params->domain_match) {
wpa_printf(MSG_INFO, "TLS: domain_match not supported");
return -1;
}
if (params->openssl_ciphers) {
wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported");
return -1;
}
if (global->my_cert_store == NULL &&
(global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
NULL) {
wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
algs[0] = CALG_RSA_KEYX;
conn->schannel_cred.cSupportedAlgs = 1;
conn->schannel_cred.palgSupportedAlgs = algs;
conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
#ifdef UNICODE
status = global->sspi->AcquireCredentialsHandleW(
NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
#else /* UNICODE */
status = global->sspi->AcquireCredentialsHandleA(
NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
#endif /* UNICODE */
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
"0x%x", __func__, (unsigned int) status);
return -1;
}
return 0;
}
unsigned int tls_capabilities(void *tls_ctx)
{
return 0;
}
int tls_get_library_version(char *buf, size_t buf_len)
{
return os_snprintf(buf, buf_len, "schannel");
}

View File

@ -20,6 +20,7 @@
#define WPA_SUPPLICANT_DRIVER_VERSION 4
#include "common/defs.h"
#include "common/ieee802_11_defs.h"
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
@ -341,7 +342,7 @@ struct wpa_driver_scan_params {
* is not needed anymore.
*/
struct wpa_driver_scan_filter {
u8 ssid[32];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
} *filter_ssids;
@ -1211,6 +1212,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
/** Driver supports IBSS with VHT datarates */
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
/** Driver supports automatic band selection */
#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL
u64 flags;
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
@ -1294,6 +1297,13 @@ struct wpa_driver_capa {
*/
#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
u32 rrm_flags;
/* Driver concurrency capabilities */
unsigned int conc_capab;
/* Maximum number of concurrent channels on 2.4 GHz */
unsigned int max_conc_chan_2_4;
/* Maximum number of concurrent channels on 5 GHz */
unsigned int max_conc_chan_5_0;
};
@ -1394,6 +1404,16 @@ enum wpa_driver_if_type {
* WPA_IF_MESH - Mesh interface
*/
WPA_IF_MESH,
/*
* WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only)
*/
WPA_IF_TDLS,
/*
* WPA_IF_IBSS - IBSS interface (used for pref freq only)
*/
WPA_IF_IBSS,
};
struct wpa_init_params {
@ -1477,6 +1497,7 @@ struct wpa_signal_info {
int above_threshold;
int current_signal;
int avg_signal;
int avg_beacon_signal;
int current_noise;
int current_txrate;
enum chan_width chanwidth;
@ -1576,6 +1597,7 @@ enum drv_br_port_attr {
enum drv_br_net_param {
DRV_BR_NET_PARAM_GARP_ACCEPT,
DRV_BR_MULTICAST_SNOOPING,
};
struct drv_acs_params {
@ -1587,6 +1609,17 @@ struct drv_acs_params {
/* Indicates whether HT40 is enabled */
int ht40_enabled;
/* Indicates whether VHT is enabled */
int vht_enabled;
/* Configured ACS channel width */
u16 ch_width;
/* ACS channel list info */
unsigned int ch_list_len;
const u8 *ch_list;
const int *freq_list;
};
@ -1925,10 +1958,12 @@ struct wpa_driver_ops {
* @data: IEEE 802.11 management frame with IEEE 802.11 header
* @data_len: Size of the management frame
* @noack: Do not wait for this frame to be acked (disable retries)
* @freq: Frequency (in MHz) to send the frame on, or 0 to let the
* driver decide
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
int noack);
int noack, unsigned int freq);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@ -2332,7 +2367,8 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*/
int (*sta_set_flags)(void *priv, const u8 *addr,
int total_flags, int flags_or, int flags_and);
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and);
/**
* set_tx_queue_params - Set TX queue parameters
@ -2655,18 +2691,6 @@ struct wpa_driver_ops {
int (*send_frame)(void *priv, const u8 *data, size_t data_len,
int encrypt);
/**
* shared_freq - Get operating frequency of shared interface(s)
* @priv: Private driver interface data
* Returns: Operating frequency in MHz, 0 if no shared operation in
* use, or -1 on failure
*
* This command can be used to request the current operating frequency
* of any virtual interface that shares the same radio to provide
* information for channel selection for other virtual interfaces.
*/
int (*shared_freq)(void *priv);
/**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
@ -3381,6 +3405,40 @@ struct wpa_driver_ops {
* indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
*/
int (*do_acs)(void *priv, struct drv_acs_params *params);
/**
* set_band - Notify driver of band selection
* @priv: Private driver interface data
* @band: The selected band(s)
* Returns 0 on success, -1 on failure
*/
int (*set_band)(void *priv, enum set_band band);
/**
* get_pref_freq_list - Get preferred frequency list for an interface
* @priv: Private driver interface data
* @if_type: Interface type
* @num: Number of channels
* @freq_list: Preferred channel frequency list encoded in MHz values
* Returns 0 on success, -1 on failure
*
* This command can be used to query the preferred frequency list from
* the driver specific to a particular interface type.
*/
int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type,
unsigned int *num, unsigned int *freq_list);
/**
* set_prob_oper_freq - Indicate probable P2P operating channel
* @priv: Private driver interface data
* @freq: Channel frequency in MHz
* Returns 0 on success, -1 on failure
*
* This command can be used to inform the driver of the operating
* frequency that an ongoing P2P group formation is likely to come up
* on. Local device is assuming P2P Client role.
*/
int (*set_prob_oper_freq)(void *priv, unsigned int freq);
};
@ -4557,10 +4615,20 @@ union wpa_event_data {
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
* @pri_channel: Selected primary channel
* @sec_channel: Selected secondary channel
* @vht_seg0_center_ch: VHT mode Segment0 center channel
* @vht_seg1_center_ch: VHT mode Segment1 center channel
* @ch_width: Selected Channel width by driver. Driver may choose to
* change hostapd configured ACS channel width due driver internal
* channel restrictions.
* hw_mode: Selected band (used with hw_mode=any)
*/
struct acs_selected_channels {
u8 pri_channel;
u8 sec_channel;
u8 vht_seg0_center_ch;
u8 vht_seg1_center_ch;
u16 ch_width;
enum hostapd_hw_mode hw_mode;
} acs_selected_channels;
};
@ -4631,6 +4699,6 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
/* NULL terminated array of linked in driver wrappers */
extern struct wpa_driver_ops *wpa_drivers[];
extern const struct wpa_driver_ops *const wpa_drivers[];
#endif /* DRIVER_H */

View File

@ -860,8 +860,7 @@ bad:
if (drv->sock >= 0)
close(drv->sock);
os_free(drv->event_buf);
if (drv != NULL)
os_free(drv);
os_free(drv);
return NULL;
}
@ -894,7 +893,8 @@ bsd_commit(void *priv)
static int
bsd_set_sta_authorized(void *priv, const u8 *addr,
int total_flags, int flags_or, int flags_and)
unsigned int total_flags, unsigned int flags_or,
unsigned int flags_and)
{
int authorized = -1;

View File

@ -710,11 +710,11 @@ static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
/* Disconnect by setting SSID to random (i.e., likely not used). */
static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
{
char ssid[32];
char ssid[SSID_MAX_LEN];
int i;
for (i = 0; i < 32; i++)
for (i = 0; i < SSID_MAX_LEN; i++)
ssid[i] = rand() & 0xff;
return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, SSID_MAX_LEN);
}
@ -807,7 +807,7 @@ static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
if (wpa_scan_get_ie(r, WLAN_EID_SSID))
return r; /* SSID IE already present */
if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
if (ssid->SsidLength == 0 || ssid->SsidLength > SSID_MAX_LEN)
return r; /* No valid SSID inside scan data */
nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);

View File

@ -110,7 +110,7 @@ struct wpa_driver_nl80211_data {
u8 bssid[ETH_ALEN];
u8 prev_bssid[ETH_ALEN];
int associated;
u8 ssid[32];
u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
enum nl80211_iftype nlmode;
enum nl80211_iftype ap_scan_as_station;
@ -145,6 +145,9 @@ struct wpa_driver_nl80211_data {
unsigned int get_features_vendor_cmd_avail:1;
unsigned int set_rekey_offload:1;
unsigned int p2p_go_ctwindow_supported:1;
unsigned int setband_vendor_cmd_avail:1;
unsigned int get_pref_freq_list:1;
unsigned int set_prob_oper_freq:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@ -169,7 +172,7 @@ struct wpa_driver_nl80211_data {
/* From failed authentication command */
int auth_freq;
u8 auth_bssid_[ETH_ALEN];
u8 auth_ssid[32];
u8 auth_ssid[SSID_MAX_LEN];
size_t auth_ssid_len;
int auth_alg;
u8 *auth_ie;
@ -232,7 +235,6 @@ int process_bss_event(struct nl_msg *msg, void *arg);
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
@ -270,5 +272,6 @@ int wpa_driver_nl80211_sched_scan(void *priv,
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
#endif /* DRIVER_NL80211_H */

View File

@ -151,7 +151,7 @@ int android_pno_stop(struct i802_bss *bss)
#ifdef ANDROID_P2P
#ifdef ANDROID_P2P_STUB
#ifdef ANDROID_LIB_STUB
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
{
@ -178,7 +178,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
return 0;
}
#endif /* ANDROID_P2P_STUB */
#endif /* ANDROID_LIB_STUB */
#endif /* ANDROID_P2P */
@ -188,33 +188,3 @@ int android_nl_socket_set_nonblocking(struct nl_handle *handle)
}
int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
{
/*
* Android ICS has very minimal genl_ctrl_resolve() implementation, so
* need to work around that.
*/
struct nl_cache *cache = NULL;
struct genl_family *nl80211 = NULL;
int id = -1;
if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
"netlink cache");
goto fail;
}
nl80211 = genl_ctrl_search_by_name(cache, name);
if (nl80211 == NULL)
goto fail;
id = genl_family_get_id(nl80211);
fail:
if (nl80211)
genl_family_put(nl80211);
if (cache)
nl_cache_free(cache);
return id;
}

View File

@ -335,6 +335,33 @@ static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
}
static int ext_feature_isset(const u8 *ext_features, int ext_features_len,
enum nl80211_ext_feature_index ftidx)
{
u8 ft_byte;
if ((int) ftidx / 8 >= ext_features_len)
return 0;
ft_byte = ext_features[ftidx / 8];
return (ft_byte & BIT(ftidx % 8)) != 0;
}
static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
struct nlattr *tb)
{
struct wpa_driver_capa *capa = info->capa;
if (tb == NULL)
return;
if (ext_feature_isset(nla_data(tb), nla_len(tb),
NL80211_EXT_FEATURE_VHT_IBSS))
capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
}
static void wiphy_info_feature_flags(struct wiphy_info_data *info,
struct nlattr *tb)
{
@ -509,6 +536,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
info->device_ap_sme = 1;
wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
wiphy_info_probe_resp_offload(capa,
tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
@ -547,22 +575,34 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
continue;
}
vinfo = nla_data(nl);
switch (vinfo->subcmd) {
case QCA_NL80211_VENDOR_SUBCMD_TEST:
drv->vendor_cmd_test_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
drv->roaming_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
drv->dfs_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
drv->get_features_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
break;
if (vinfo->vendor_id == OUI_QCA) {
switch (vinfo->subcmd) {
case QCA_NL80211_VENDOR_SUBCMD_TEST:
drv->vendor_cmd_test_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
drv->roaming_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
drv->dfs_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
drv->get_features_vendor_cmd_avail = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST:
drv->get_pref_freq_list = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL:
drv->set_prob_oper_freq = 1;
break;
case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
drv->capa.flags |=
WPA_DRIVER_FLAGS_ACS_OFFLOAD;
break;
case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
drv->setband_vendor_cmd_avail = 1;
break;
}
}
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
@ -717,6 +757,7 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
struct features_info {
u8 *flags;
size_t flags_len;
struct wpa_driver_capa *capa;
};
@ -742,6 +783,19 @@ static int features_info_handler(struct nl_msg *msg, void *arg)
info->flags = nla_data(attr);
info->flags_len = nla_len(attr);
}
attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA];
if (attr)
info->capa->conc_capab = nla_get_u32(attr);
attr = tb_vendor[
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND];
if (attr)
info->capa->max_conc_chan_2_4 = nla_get_u32(attr);
attr = tb_vendor[
QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND];
if (attr)
info->capa->max_conc_chan_5_0 = nla_get_u32(attr);
}
return NL_SKIP;
@ -776,12 +830,16 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
}
os_memset(&info, 0, sizeof(info));
info.capa = &drv->capa;
ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
if (ret || !info.flags)
return;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
}

View File

@ -271,6 +271,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
struct nlattr *ptk_kek)
{
union wpa_event_data event;
const u8 *ssid;
u16 status_code;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
@ -331,6 +332,16 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
if (req_ie) {
event.assoc_info.req_ies = nla_data(req_ie);
event.assoc_info.req_ies_len = nla_len(req_ie);
if (cmd == NL80211_CMD_ROAM) {
ssid = nl80211_get_ie(event.assoc_info.req_ies,
event.assoc_info.req_ies_len,
WLAN_EID_SSID);
if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
drv->ssid_len = ssid[1];
os_memcpy(drv->ssid, ssid + 2, ssid[1]);
}
}
}
if (resp_ie) {
event.assoc_info.resp_ies = nla_data(resp_ie);
@ -1480,6 +1491,25 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
}
static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode)
{
switch (hw_mode) {
case QCA_ACS_MODE_IEEE80211B:
return HOSTAPD_MODE_IEEE80211B;
case QCA_ACS_MODE_IEEE80211G:
return HOSTAPD_MODE_IEEE80211G;
case QCA_ACS_MODE_IEEE80211A:
return HOSTAPD_MODE_IEEE80211A;
case QCA_ACS_MODE_IEEE80211AD:
return HOSTAPD_MODE_IEEE80211AD;
case QCA_ACS_MODE_IEEE80211ANY:
return HOSTAPD_MODE_IEEE80211ANY;
default:
return NUM_HOSTAPD_MODES;
}
}
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
{
@ -1500,6 +1530,39 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
event.acs_selected_channels.sec_channel =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
event.acs_selected_channels.vht_seg0_center_ch =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
event.acs_selected_channels.vht_seg1_center_ch =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
event.acs_selected_channels.ch_width =
nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode);
if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES ||
event.acs_selected_channels.hw_mode ==
HOSTAPD_MODE_IEEE80211ANY) {
wpa_printf(MSG_DEBUG,
"nl80211: Invalid hw_mode %d in ACS selection event",
hw_mode);
return;
}
}
wpa_printf(MSG_INFO,
"nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
event.acs_selected_channels.pri_channel,
event.acs_selected_channels.sec_channel,
event.acs_selected_channels.ch_width,
event.acs_selected_channels.vht_seg0_center_ch,
event.acs_selected_channels.vht_seg1_center_ch,
event.acs_selected_channels.hw_mode);
/* Ignore ACS channel list check for backwards compatibility */
wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
}

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