Update hostapd/wpa_supplicant to version 2.5.
Tested by several people on current@/wireless@. Relnotes: yes
This commit is contained in:
commit
325151a32e
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
398
contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch
Normal file
398
contrib/wpa/patches/openssl-0.9.8zf-tls-extensions.patch
Normal 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
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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(¶ms, 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, ¶ms);
|
||||
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, ¶ms);
|
||||
os_free(channels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
@ -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 */
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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),
|
||||
|
@ -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]);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
100
contrib/wpa/src/crypto/sha384-prf.c
Normal file
100
contrib/wpa/src/crypto/sha384-prf.c
Normal 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));
|
||||
}
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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
@ -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");
|
||||
}
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user