Merge "Revert "wpa_supplicant: Explicitly enable 802.11n and 802.11d for qcwcn"" into jb-mr1-dev
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 107f381..ee153d0 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -33,6 +33,10 @@
L_CFLAGS += -DANDROID_P2P
endif
+# Use Android specific directory for control interface sockets
+L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
+L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/hostapd\"
+
# To force sizeof(enum) = 4
ifeq ($(TARGET_ARCH),arm)
L_CFLAGS += -mabi=aapcs-linux
@@ -100,6 +104,7 @@
NEED_AES=y
NEED_MD5=y
NEED_SHA1=y
+NEED_SHA256=y
OBJS += src/drivers/drivers.c
L_CFLAGS += -DHOSTAPD
@@ -145,6 +150,7 @@
else
OBJS += src/radius/radius.c
OBJS += src/radius/radius_client.c
+OBJS += src/radius/radius_das.c
endif
ifdef CONFIG_NO_ACCOUNTING
@@ -157,6 +163,12 @@
L_CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += src/ap/vlan_init.c
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_util.c
+endif
+L_CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@@ -199,10 +211,23 @@
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_IEEE80211V
+L_CFLAGS += -DCONFIG_IEEE80211V
+OBJS += src/ap/wnm_ap.c
+endif
+
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+endif
+
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
include $(LOCAL_PATH)/src/drivers/drivers.mk
OBJS += $(DRV_AP_OBJS)
@@ -239,6 +264,14 @@
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+L_CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+endif
+
ifdef CONFIG_EAP_PEAP
L_CFLAGS += -DEAP_SERVER_PEAP
OBJS += src/eap_server/eap_server_peap.c
@@ -472,6 +505,15 @@
CONFIG_TLS=openssl
endif
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
OBJS += src/crypto/tls_openssl.c
@@ -555,6 +597,9 @@
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
L_CFLAGS += -DCONFIG_TLS_INTERNAL
@@ -669,14 +714,19 @@
SHA1OBJS =
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
ifdef NEED_FIPS186_2_PRF
SHA1OBJS += src/crypto/fips_prf_internal.c
endif
endif
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
ifdef NEED_T_PRF
SHA1OBJS += src/crypto/sha1-tprf.c
endif
@@ -715,10 +765,17 @@
endif
ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
OBJS += src/crypto/sha256.c
+endif
+OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
OBJS += src/crypto/sha256-internal.c
endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += src/crypto/sha256-tlsprf.c
+endif
endif
ifdef NEED_DH_GROUPS
@@ -738,6 +795,7 @@
else
OBJS += src/crypto/random.c
HOBJS += src/crypto/random.c
+HOBJS += src/utils/eloop.c
HOBJS += $(SHA1OBJS)
HOBJS += src/crypto/md5.c
endif
@@ -776,11 +834,27 @@
OBJS += src/ap/ieee802_11_ht.c
endif
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
+
ifdef CONFIG_P2P_MANAGER
L_CFLAGS += -DCONFIG_P2P_MANAGER
OBJS += src/ap/p2p_hostapd.c
endif
+ifdef CONFIG_HS20
+L_CFLAGS += -DCONFIG_HS20
+OBJS += src/ap/hs20.c
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+L_CFLAGS += -DCONFIG_INTERWORKING
+OBJS += src/common/gas.c
+OBJS += src/ap/gas_serv.c
+endif
+
OBJS += src/drivers/driver_common.c
ifdef CONFIG_NO_STDOUT_DEBUG
diff --git a/hostapd/Makefile b/hostapd/Makefile
index b43aa75..f5dfce0 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -123,6 +123,12 @@
CFLAGS += -DCONFIG_NO_VLAN
else
OBJS += ../src/ap/vlan_init.o
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_util.o
+endif
+CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
endif
ifdef CONFIG_NO_CTRL_IFACE
@@ -165,6 +171,11 @@
NEED_AES_UNWRAP=y
endif
+ifdef CONFIG_IEEE80211V
+CFLAGS += -DCONFIG_IEEE80211V
+OBJS += ../src/ap/wnm_ap.o
+endif
+
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
endif
@@ -212,6 +223,14 @@
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+endif
+
ifdef CONFIG_EAP_PEAP
CFLAGS += -DEAP_SERVER_PEAP
OBJS += ../src/eap_server/eap_server_peap.o
@@ -649,14 +668,19 @@
endif
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
SHA1OBJS += ../src/crypto/fips_prf_internal.o
endif
endif
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -696,7 +720,10 @@
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
OBJS += ../src/crypto/sha256.o
+endif
+OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
OBJS += ../src/crypto/sha256-internal.o
endif
@@ -770,6 +797,12 @@
OBJS += ../src/ap/p2p_hostapd.o
endif
+ifdef CONFIG_HS20
+CFLAGS += -DCONFIG_HS20
+OBJS += ../src/ap/hs20.o
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
CFLAGS += -DCONFIG_INTERWORKING
OBJS += ../src/common/gas.o
@@ -792,6 +825,12 @@
CFLAGS += -DCONFIG_DEBUG_FILE
endif
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index eebbaa6..0a24ec3 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -167,7 +167,7 @@
if (*pos != '\0')
vlan_id = atoi(pos);
- newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
+ newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
if (newacl == NULL) {
wpa_printf(MSG_ERROR, "MAC list reallocation failed");
fclose(f);
@@ -475,7 +475,7 @@
int ret;
static int server_index = 1;
- nserv = os_realloc(*server, (*num_server + 1) * sizeof(*nserv));
+ nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
if (nserv == NULL)
return -1;
@@ -567,25 +567,21 @@
const char *val)
{
char *secret;
- size_t len;
secret = os_strchr(val, ' ');
if (secret == NULL)
return -1;
secret++;
- len = os_strlen(secret);
if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
return -1;
os_free(bss->radius_das_shared_secret);
- bss->radius_das_shared_secret = os_malloc(len);
+ bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
if (bss->radius_das_shared_secret == NULL)
return -1;
-
- os_memcpy(bss->radius_das_shared_secret, secret, len);
- bss->radius_das_shared_secret_len = len;
+ bss->radius_das_shared_secret_len = os_strlen(secret);
return 0;
}
@@ -673,6 +669,8 @@
*end = '\0';
if (os_strcmp(start, "CCMP") == 0)
val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
else if (os_strcmp(start, "WEP104") == 0)
@@ -784,8 +782,8 @@
if (*ifname == '\0')
return -1;
- bss = os_realloc(conf->bss, (conf->num_bss + 1) *
- sizeof(struct hostapd_bss_config));
+ bss = os_realloc_array(conf->bss, conf->num_bss + 1,
+ sizeof(struct hostapd_bss_config));
if (bss == NULL) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for "
"multi-BSS entry");
@@ -909,78 +907,6 @@
}
-static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
- char *val)
-{
- int num, v;
- char *pos;
- struct hostapd_wmm_ac_params *ac;
-
- /* skip 'wme_ac_' or 'wmm_ac_' prefix */
- pos = name + 7;
- if (os_strncmp(pos, "be_", 3) == 0) {
- num = 0;
- pos += 3;
- } else if (os_strncmp(pos, "bk_", 3) == 0) {
- num = 1;
- pos += 3;
- } else if (os_strncmp(pos, "vi_", 3) == 0) {
- num = 2;
- pos += 3;
- } else if (os_strncmp(pos, "vo_", 3) == 0) {
- num = 3;
- pos += 3;
- } else {
- wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
- return -1;
- }
-
- ac = &conf->wmm_ac_params[num];
-
- if (os_strcmp(pos, "aifs") == 0) {
- v = atoi(val);
- if (v < 1 || v > 255) {
- wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
- return -1;
- }
- ac->aifs = v;
- } else if (os_strcmp(pos, "cwmin") == 0) {
- v = atoi(val);
- if (v < 0 || v > 12) {
- 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) {
- wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
- return -1;
- }
- ac->cwmax = v;
- } else if (os_strcmp(pos, "txop_limit") == 0) {
- v = atoi(val);
- if (v < 0 || v > 0xffff) {
- wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
- return -1;
- }
- ac->txop_limit = v;
- } else if (os_strcmp(pos, "acm") == 0) {
- v = atoi(val);
- if (v < 0 || v > 1) {
- wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
- return -1;
- }
- ac->admission_control_mandatory = v;
- } else {
- wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
- return -1;
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_IEEE80211R
static int add_r0kh(struct hostapd_bss_config *bss, char *value)
{
@@ -1268,10 +1194,10 @@
if (conf->ieee80211n && bss->wpa &&
!(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
- !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
bss->disable_11n = 1;
wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
- "requires CCMP to be enabled, disabling HT "
+ "requires CCMP/GCMP to be enabled, disabling HT "
"capabilities");
}
#endif /* CONFIG_IEEE80211N */
@@ -1288,8 +1214,27 @@
"disabled");
bss->wps_state = 0;
}
+
+ if (bss->wps_state && bss->wpa &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+ wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+ "WPA2/CCMP forced WPS to be disabled");
+ bss->wps_state = 0;
+ }
#endif /* CONFIG_WPS2 */
+#ifdef CONFIG_HS20
+ if (bss->hs20 &&
+ (!(bss->wpa & 2) ||
+ !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+ wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+ "configuration is required for Hotspot 2.0 "
+ "functionality");
+ return -1;
+ }
+#endif /* CONFIG_HS20 */
+
return 0;
}
@@ -1330,9 +1275,9 @@
}
len /= 2;
- rc = os_realloc(bss->roaming_consortium,
- sizeof(struct hostapd_roaming_consortium) *
- (bss->roaming_consortium_count + 1));
+ rc = os_realloc_array(bss->roaming_consortium,
+ bss->roaming_consortium_count + 1,
+ sizeof(struct hostapd_roaming_consortium));
if (rc == NULL)
return -1;
@@ -1346,50 +1291,387 @@
}
-static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
- int line)
+static int parse_lang_string(struct hostapd_lang_string **array,
+ unsigned int *count, char *pos)
{
char *sep;
size_t clen, nlen;
- struct hostapd_venue_name *vn;
+ struct hostapd_lang_string *ls;
sep = os_strchr(pos, ':');
if (sep == NULL)
- goto fail;
+ return -1;
*sep++ = '\0';
clen = os_strlen(pos);
if (clen < 2)
- goto fail;
+ return -1;
nlen = os_strlen(sep);
if (nlen > 252)
- goto fail;
-
- vn = os_realloc(bss->venue_name,
- sizeof(struct hostapd_venue_name) *
- (bss->venue_name_count + 1));
- if (vn == NULL)
return -1;
- bss->venue_name = vn;
- vn = &bss->venue_name[bss->venue_name_count];
- bss->venue_name_count++;
+ ls = os_realloc_array(*array, *count + 1,
+ sizeof(struct hostapd_lang_string));
+ if (ls == NULL)
+ return -1;
- os_memset(vn->lang, 0, sizeof(vn->lang));
- os_memcpy(vn->lang, pos, clen);
- vn->name_len = nlen;
- os_memcpy(vn->name, sep, nlen);
+ *array = ls;
+ ls = &(*array)[*count];
+ (*count)++;
+
+ os_memset(ls->lang, 0, sizeof(ls->lang));
+ os_memcpy(ls->lang, pos, clen);
+ ls->name_len = nlen;
+ os_memcpy(ls->name, sep, nlen);
+
+ return 0;
+}
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+ int line)
+{
+ if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+ line, pos);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ size_t count;
+ char *pos;
+ u8 *info = NULL, *ipos;
+
+ /* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
+
+ count = 1;
+ for (pos = buf; *pos; pos++) {
+ if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
+ goto fail;
+ if (*pos == ';')
+ count++;
+ }
+ if (1 + count * 3 > 0x7f)
+ goto fail;
+
+ info = os_zalloc(2 + 3 + count * 3);
+ if (info == NULL)
+ return -1;
+
+ ipos = info;
+ *ipos++ = 0; /* GUD - Version 1 */
+ *ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
+ *ipos++ = 0; /* PLMN List IEI */
+ /* ext(b8) | Length of PLMN List value contents(b7..1) */
+ *ipos++ = 1 + count * 3;
+ *ipos++ = count; /* Number of PLMNs */
+
+ pos = buf;
+ while (pos && *pos) {
+ char *mcc, *mnc;
+ size_t mnc_len;
+
+ mcc = pos;
+ mnc = os_strchr(pos, ',');
+ if (mnc == NULL)
+ goto fail;
+ *mnc++ = '\0';
+ pos = os_strchr(mnc, ';');
+ if (pos)
+ *pos++ = '\0';
+
+ mnc_len = os_strlen(mnc);
+ if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
+ goto fail;
+
+ /* BC coded MCC,MNC */
+ /* MCC digit 2 | MCC digit 1 */
+ *ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
+ /* MNC digit 3 | MCC digit 3 */
+ *ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
+ (mcc[2] - '0');
+ /* MNC digit 2 | MNC digit 1 */
+ *ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
+ }
+
+ os_free(bss->anqp_3gpp_cell_net);
+ bss->anqp_3gpp_cell_net = info;
+ bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
+ wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
+ bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
return 0;
fail:
- wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
- line, pos);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
+ line, buf);
+ os_free(info);
return -1;
}
+
+
+static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
+{
+ struct hostapd_nai_realm_data *realm;
+ size_t i, j, len;
+ int *offsets;
+ char *pos, *end, *rpos;
+
+ offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
+ sizeof(int));
+ if (offsets == NULL)
+ return -1;
+
+ for (i = 0; i < bss->nai_realm_count; i++) {
+ realm = &bss->nai_realm_data[i];
+ for (j = 0; j < MAX_NAI_REALMS; j++) {
+ offsets[i * MAX_NAI_REALMS + j] =
+ realm->realm[j] ?
+ realm->realm[j] - realm->realm_buf : -1;
+ }
+ }
+
+ realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
+ sizeof(struct hostapd_nai_realm_data));
+ if (realm == NULL) {
+ os_free(offsets);
+ return -1;
+ }
+ bss->nai_realm_data = realm;
+
+ /* patch the pointers after realloc */
+ for (i = 0; i < bss->nai_realm_count; i++) {
+ realm = &bss->nai_realm_data[i];
+ for (j = 0; j < MAX_NAI_REALMS; j++) {
+ int offs = offsets[i * MAX_NAI_REALMS + j];
+ if (offs >= 0)
+ realm->realm[j] = realm->realm_buf + offs;
+ else
+ realm->realm[j] = NULL;
+ }
+ }
+ os_free(offsets);
+
+ realm = &bss->nai_realm_data[bss->nai_realm_count];
+ os_memset(realm, 0, sizeof(*realm));
+
+ pos = buf;
+ realm->encoding = atoi(pos);
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ end = os_strchr(pos, ',');
+ if (end) {
+ len = end - pos;
+ *end = '\0';
+ } else {
+ len = os_strlen(pos);
+ }
+
+ if (len > MAX_NAI_REALMLEN) {
+ wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
+ "characters)", (int) len, MAX_NAI_REALMLEN);
+ goto fail;
+ }
+ os_memcpy(realm->realm_buf, pos, len);
+
+ if (end)
+ pos = end + 1;
+ else
+ pos = NULL;
+
+ while (pos && *pos) {
+ struct hostapd_nai_realm_eap *eap;
+
+ if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
+ wpa_printf(MSG_ERROR, "Too many EAP methods");
+ goto fail;
+ }
+
+ eap = &realm->eap_method[realm->eap_method_count];
+ realm->eap_method_count++;
+
+ end = os_strchr(pos, ',');
+ if (end == NULL)
+ end = pos + os_strlen(pos);
+
+ eap->eap_method = atoi(pos);
+ for (;;) {
+ pos = os_strchr(pos, '[');
+ if (pos == NULL || pos > end)
+ break;
+ pos++;
+ if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
+ wpa_printf(MSG_ERROR, "Too many auth params");
+ goto fail;
+ }
+ eap->auth_id[eap->num_auths] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL || pos > end)
+ goto fail;
+ pos++;
+ eap->auth_val[eap->num_auths] = atoi(pos);
+ pos = os_strchr(pos, ']');
+ if (pos == NULL || pos > end)
+ goto fail;
+ pos++;
+ eap->num_auths++;
+ }
+
+ if (*end != ',')
+ break;
+
+ pos = end + 1;
+ }
+
+ /* Split realm list into null terminated realms */
+ rpos = realm->realm_buf;
+ i = 0;
+ while (*rpos) {
+ if (i >= MAX_NAI_REALMS) {
+ wpa_printf(MSG_ERROR, "Too many realms");
+ goto fail;
+ }
+ realm->realm[i++] = rpos;
+ rpos = os_strchr(rpos, ';');
+ if (rpos == NULL)
+ break;
+ *rpos++ = '\0';
+ }
+
+ bss->nai_realm_count++;
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
+ return -1;
+}
+
#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ u8 *conn_cap;
+ char *pos;
+
+ if (bss->hs20_connection_capability_len >= 0xfff0)
+ return -1;
+
+ conn_cap = os_realloc(bss->hs20_connection_capability,
+ bss->hs20_connection_capability_len + 4);
+ if (conn_cap == NULL)
+ return -1;
+
+ bss->hs20_connection_capability = conn_cap;
+ conn_cap += bss->hs20_connection_capability_len;
+ pos = buf;
+ conn_cap[0] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ WPA_PUT_LE16(conn_cap + 1, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ conn_cap[3] = atoi(pos);
+ bss->hs20_connection_capability_len += 4;
+
+ return 0;
+}
+
+
+static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
+ int line)
+{
+ u8 *wan_metrics;
+ char *pos;
+
+ /* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
+
+ wan_metrics = os_zalloc(13);
+ if (wan_metrics == NULL)
+ return -1;
+
+ pos = buf;
+ /* WAN Info */
+ if (hexstr2bin(pos, wan_metrics, 1) < 0)
+ goto fail;
+ pos += 2;
+ if (*pos != ':')
+ goto fail;
+ pos++;
+
+ /* Downlink Speed */
+ WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Uplink Speed */
+ WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Downlink Load */
+ wan_metrics[9] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* Uplink Load */
+ wan_metrics[10] = atoi(pos);
+ pos = os_strchr(pos, ':');
+ if (pos == NULL)
+ goto fail;
+ pos++;
+
+ /* LMD */
+ WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
+
+ os_free(bss->hs20_wan_metrics);
+ bss->hs20_wan_metrics = wan_metrics;
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
+ line, pos);
+ os_free(wan_metrics);
+ return -1;
+}
+
+
+static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
+ char *pos, int line)
+{
+ if (parse_lang_string(&bss->hs20_oper_friendly_name,
+ &bss->hs20_oper_friendly_name_count, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_oper_friendly_name '%s'", line, pos);
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_HS20 */
+
+
#ifdef CONFIG_WPS_NFC
static struct wpabuf * hostapd_parse_bin(const char *buf)
{
@@ -1470,9 +1752,22 @@
} else {
os_memcpy(bss->ssid.ssid, pos,
bss->ssid.ssid_len);
- bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
bss->ssid.ssid_set = 1;
}
+ } 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) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+ "'%s'", line, pos);
+ errors++;
+ } else {
+ os_memcpy(bss->ssid.ssid, str, slen);
+ bss->ssid.ssid_len = slen;
+ bss->ssid.ssid_set = 1;
+ }
+ os_free(str);
} else if (os_strcmp(buf, "macaddr_acl") == 0) {
bss->macaddr_acl = atoi(pos);
if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
@@ -2120,6 +2415,15 @@
"read VLAN file '%s'", line, pos);
errors++;
}
+ } else if (os_strcmp(buf, "vlan_naming") == 0) {
+ bss->ssid.vlan_naming = atoi(pos);
+ if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
+ bss->ssid.vlan_naming < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "naming scheme %d", line,
+ bss->ssid.vlan_naming);
+ errors++;
+ }
#ifdef CONFIG_FULL_DYNAMIC_VLAN
} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
bss->ssid.vlan_tagged_interface = os_strdup(pos);
@@ -2142,7 +2446,8 @@
bss->wmm_uapsd = atoi(pos);
} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
os_strncmp(buf, "wmm_ac_", 7) == 0) {
- if (hostapd_config_wmm_ac(conf, buf, pos)) {
+ if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
+ pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
"ac item", line);
errors++;
@@ -2200,8 +2505,13 @@
"vht_capab", line);
errors++;
}
+ } else if (os_strcmp(buf, "require_vht") == 0) {
+ conf->require_vht = atoi(pos);
} else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
- conf->vht_oper_chwidth = atoi(pos);
+ conf->vht_oper_chwidth = atoi(pos);
+ } else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
+ {
+ conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -2429,6 +2739,92 @@
} else if (os_strcmp(buf, "venue_name") == 0) {
if (parse_venue_name(bss, pos, line) < 0)
errors++;
+ } else if (os_strcmp(buf, "network_auth_type") == 0) {
+ u8 auth_type;
+ u16 redirect_url_len;
+ if (hexstr2bin(pos, &auth_type, 1)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "network_auth_type '%s'",
+ line, pos);
+ errors++;
+ return errors;
+ }
+ if (auth_type == 0 || auth_type == 2)
+ redirect_url_len = os_strlen(pos + 2);
+ else
+ redirect_url_len = 0;
+ os_free(bss->network_auth_type);
+ bss->network_auth_type =
+ os_malloc(redirect_url_len + 3 + 1);
+ if (bss->network_auth_type == NULL) {
+ errors++;
+ return errors;
+ }
+ *bss->network_auth_type = auth_type;
+ WPA_PUT_LE16(bss->network_auth_type + 1,
+ redirect_url_len);
+ if (redirect_url_len)
+ os_memcpy(bss->network_auth_type + 3,
+ pos + 2, redirect_url_len);
+ bss->network_auth_type_len = 3 + redirect_url_len;
+ } else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
+ if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
+ {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "ipaddr_type_availability '%s'",
+ line, pos);
+ bss->ipaddr_type_configured = 0;
+ errors++;
+ return errors;
+ }
+ bss->ipaddr_type_configured = 1;
+ } else if (os_strcmp(buf, "domain_name") == 0) {
+ int j, num_domains, domain_len, domain_list_len = 0;
+ char *tok_start, *tok_prev;
+ u8 *domain_list, *domain_ptr;
+
+ domain_list_len = os_strlen(pos) + 1;
+ domain_list = os_malloc(domain_list_len);
+ if (domain_list == NULL) {
+ errors++;
+ return errors;
+ }
+
+ domain_ptr = domain_list;
+ tok_prev = pos;
+ num_domains = 1;
+ while ((tok_prev = os_strchr(tok_prev, ','))) {
+ num_domains++;
+ tok_prev++;
+ }
+ tok_prev = pos;
+ for (j = 0; j < num_domains; j++) {
+ tok_start = os_strchr(tok_prev, ',');
+ if (tok_start) {
+ domain_len = tok_start - tok_prev;
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev,
+ domain_len);
+ domain_ptr += domain_len + 1;
+ tok_prev = ++tok_start;
+ } else {
+ domain_len = os_strlen(tok_prev);
+ *domain_ptr = domain_len;
+ os_memcpy(domain_ptr + 1, tok_prev,
+ domain_len);
+ domain_ptr += domain_len + 1;
+ }
+ }
+
+ os_free(bss->domain_name);
+ bss->domain_name = domain_list;
+ bss->domain_name_len = domain_list_len;
+ } else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
+ if (parse_3gpp_cell_net(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "nai_realm") == 0) {
+ if (parse_nai_realm(bss, pos, line) < 0)
+ errors++;
} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
bss->gas_frag_limit = atoi(pos);
} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
@@ -2439,6 +2835,81 @@
os_free(bss->dump_msk_file);
bss->dump_msk_file = os_strdup(pos);
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_HS20
+ } else if (os_strcmp(buf, "hs20") == 0) {
+ bss->hs20 = atoi(pos);
+ } else if (os_strcmp(buf, "disable_dgaf") == 0) {
+ bss->disable_dgaf = atoi(pos);
+ } else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
+ if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
+ errors++;
+ } else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
+ if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
+ errors++;
+ return errors;
+ }
+ } else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
+ if (hs20_parse_conn_capab(bss, pos, line) < 0) {
+ errors++;
+ return errors;
+ }
+ } else if (os_strcmp(buf, "hs20_operating_class") == 0) {
+ u8 *oper_class;
+ size_t oper_class_len;
+ oper_class_len = os_strlen(pos);
+ if (oper_class_len < 2 || (oper_class_len & 0x01)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_operating_class '%s'",
+ line, pos);
+ errors++;
+ return errors;
+ }
+ oper_class_len /= 2;
+ oper_class = os_malloc(oper_class_len);
+ if (oper_class == NULL) {
+ errors++;
+ return errors;
+ }
+ if (hexstr2bin(pos, oper_class, oper_class_len)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "hs20_operating_class '%s'",
+ line, pos);
+ os_free(oper_class);
+ errors++;
+ return errors;
+ }
+ os_free(bss->hs20_operating_class);
+ bss->hs20_operating_class = oper_class;
+ bss->hs20_operating_class_len = oper_class_len;
+#endif /* CONFIG_HS20 */
+ } else if (os_strcmp(buf, "vendor_elements") == 0) {
+ struct wpabuf *elems;
+ size_t len = os_strlen(pos);
+ if (len & 0x01) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "vendor_elements '%s'", line, pos);
+ return 1;
+ }
+ len /= 2;
+ if (len == 0) {
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = NULL;
+ return 0;
+ }
+
+ elems = wpabuf_alloc(len);
+ if (elems == NULL)
+ return 1;
+
+ if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+ wpabuf_free(elems);
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "vendor_elements '%s'", line, pos);
+ return 1;
+ }
+
+ wpabuf_free(bss->vendor_elements);
+ bss->vendor_elements = elems;
} else {
wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
"item '%s'", line, buf);
@@ -2472,6 +2943,9 @@
}
if (pairwise & WPA_CIPHER_TKIP)
bss->wpa_group = WPA_CIPHER_TKIP;
+ else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+ WPA_CIPHER_GCMP)
+ bss->wpa_group = WPA_CIPHER_GCMP;
else
bss->wpa_group = WPA_CIPHER_CCMP;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 7587e03..1b8bede 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -523,7 +523,8 @@
ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
"ssid=%s\n",
MAC2STR(hapd->own_addr),
- hapd->conf->ssid.ssid);
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
@@ -618,6 +619,12 @@
return pos - buf;
pos += ret;
} else if (hapd->conf->wpa &&
+ hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ } else if (hapd->conf->wpa &&
hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
if (ret < 0 || ret >= end - pos)
@@ -637,6 +644,12 @@
return pos - buf;
pos += ret;
}
+ if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "GCMP ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "TKIP ");
if (ret < 0 || ret >= end - pos)
@@ -662,6 +675,12 @@
return pos - buf;
pos += ret;
}
+ if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "GCMP ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "TKIP ");
if (ret < 0 || ret >= end - pos)
@@ -746,6 +765,36 @@
}
+static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
+{
+ if (hostapd_enable_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Enabling of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
+{
+ if (hostapd_reload_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Reloading of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
+{
+ if (hostapd_disable_iface(iface) < 0) {
+ wpa_printf(MSG_ERROR, "Disabling of interface failed");
+ return -1;
+ }
+ return 0;
+}
+
+
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -898,6 +947,15 @@
} else if (os_strncmp(buf, "GET ", 4) == 0) {
reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
reply_size);
+ } else if (os_strncmp(buf, "ENABLE", 6) == 0) {
+ if (hostapd_ctrl_iface_enable(hapd->iface))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "RELOAD", 6) == 0) {
+ if (hostapd_ctrl_iface_reload(hapd->iface))
+ reply_len = -1;
+ } else if (os_strncmp(buf, "DISABLE", 7) == 0) {
+ if (hostapd_ctrl_iface_disable(hapd->iface))
+ reply_len = -1;
} else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -1091,6 +1149,220 @@
}
+static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_add_iface(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
+ char *buf)
+{
+ if (hostapd_remove_iface(interfaces, buf) < 0) {
+ wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
+ return -1;
+ }
+ return 0;
+}
+
+
+static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ void *interfaces = eloop_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char reply[24];
+ int reply_len;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+
+ os_memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (os_strcmp(buf, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (os_strncmp(buf, "ADD ", 4) == 0) {
+ if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
+ if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
+ reply_len = -1;
+ } else {
+ wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
+ "ignored");
+ reply_len = -1;
+ }
+
+ if (reply_len < 0) {
+ os_memcpy(reply, "FAIL\n", 5);
+ reply_len = 5;
+ }
+
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+}
+
+
+static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
+{
+ char *buf;
+ size_t len;
+
+ if (interface->global_iface_path == NULL)
+ return NULL;
+
+ len = os_strlen(interface->global_iface_path) +
+ os_strlen(interface->global_iface_name) + 2;
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+
+ os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
+ interface->global_iface_name);
+ buf[len - 1] = '\0';
+ return buf;
+}
+
+
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+ struct sockaddr_un addr;
+ int s = -1;
+ char *fname = NULL;
+
+ if (interface->global_iface_path == NULL) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
+ return 0;
+ }
+
+ if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ }
+
+ if (os_strlen(interface->global_iface_path) + 1 +
+ os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
+ goto fail;
+
+ s = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+ addr.sun_family = AF_UNIX;
+ fname = hostapd_global_ctrl_iface_path(interface);
+ if (fname == NULL)
+ goto fail;
+ os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+ strerror(errno));
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+ " allow connections - assuming it was left"
+ "over from forced program termination");
+ if (unlink(fname) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ fname);
+ goto fail;
+ }
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'", fname);
+ } else {
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+ "be in use - cannot override it");
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+ "not used anymore", fname);
+ os_free(fname);
+ fname = NULL;
+ goto fail;
+ }
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ os_free(fname);
+
+ interface->global_ctrl_sock = s;
+ eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+ interface, NULL);
+
+ return 0;
+
+fail:
+ if (s >= 0)
+ close(s);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+ return -1;
+}
+
+
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
+{
+ char *fname = NULL;
+
+ if (interfaces->global_ctrl_sock > -1) {
+ eloop_unregister_read_sock(interfaces->global_ctrl_sock);
+ close(interfaces->global_ctrl_sock);
+ interfaces->global_ctrl_sock = -1;
+ fname = hostapd_global_ctrl_iface_path(interfaces);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+
+ if (interfaces->global_iface_path &&
+ rmdir(interfaces->global_iface_path) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ perror("rmdir[ctrl_interface]");
+ }
+ }
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+ }
+}
+
+
static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
const char *buf, size_t len)
{
diff --git a/hostapd/ctrl_iface.h b/hostapd/ctrl_iface.h
index 64a5080..3341a66 100644
--- a/hostapd/ctrl_iface.h
+++ b/hostapd/ctrl_iface.h
@@ -12,6 +12,8 @@
#ifndef CONFIG_NO_CTRL_IFACE
int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
#else /* CONFIG_NO_CTRL_IFACE */
static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
{
@@ -21,6 +23,17 @@
static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
{
}
+
+static inline int
+hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+ return 0;
+}
+
+static inline void
+hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
+{
+}
#endif /* CONFIG_NO_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 9c5b13a..204aa76 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -167,6 +167,10 @@
# automatically create bridge and VLAN interfaces if necessary.
#CONFIG_FULL_DYNAMIC_VLAN=y
+# Use netlink-based kernel API for VLAN operations instead of ioctl()
+# Note: This requires libnl 3.1 or newer.
+#CONFIG_VLAN_NETLINK=y
+
# Remove support for dumping state into a file on SIGUSR1 signal
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
@@ -257,3 +261,9 @@
# This can be used to enable functionality to improve interworking with
# external networks.
#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Enable SQLite database support in hlr_auc_gw
+#CONFIG_SQLITE=y
diff --git a/hostapd/eap_register.c b/hostapd/eap_register.c
index 089c7b2..0a7ff91 100644
--- a/hostapd/eap_register.c
+++ b/hostapd/eap_register.c
@@ -39,6 +39,11 @@
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
+#ifdef EAP_SERVER_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 516d859..e04e2e9 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -43,6 +43,9 @@
#include "includes.h"
#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "crypto/milenage.h"
@@ -75,6 +78,7 @@
u8 opc[16];
u8 amf[2];
u8 sqn[6];
+ int set;
};
static struct milenage_parameters *milenage_db = NULL;
@@ -89,6 +93,144 @@
#define EAP_AKA_CK_LEN 16
+#ifdef CONFIG_SQLITE
+
+static sqlite3 *sqlite_db = NULL;
+static struct milenage_parameters db_tmp_milenage;
+
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_milenage(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE milenage("
+ " imsi INTEGER PRIMARY KEY NOT NULL,"
+ " ki CHAR(32) NOT NULL,"
+ " opc CHAR(32) NOT NULL,"
+ " amf CHAR(4) NOT NULL,"
+ " sqn CHAR(12) NOT NULL"
+ ");";
+
+ printf("Adding database table for milenage information\n");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ printf("SQLite error: %s\n", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+ sqlite3 *db;
+
+ if (sqlite3_open(db_file, &db)) {
+ printf("Failed to open database %s: %s\n",
+ db_file, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "milenage") &&
+ db_table_create_milenage(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+
+static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct milenage_parameters *m = ctx;
+ int i;
+
+ m->set = 1;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
+ printf("Invalid ki value in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
+ printf("Invalid opcvalue in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
+ printf("Invalid amf value in database\n");
+ return -1;
+ }
+
+ if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
+ hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
+ printf("Invalid sqn value in database\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
+{
+ char cmd[128];
+ unsigned long long imsi;
+
+ os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
+ imsi = atoll(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);
+ if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
+ NULL) != SQLITE_OK)
+ return NULL;
+
+ if (!db_tmp_milenage.set)
+ return NULL;
+ return &db_tmp_milenage;
+}
+
+
+static int db_update_milenage_sqn(struct milenage_parameters *m)
+{
+ char cmd[128], val[13], *pos;
+
+ pos = val;
+ pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
+ *pos = '\0';
+ os_snprintf(cmd, sizeof(cmd),
+ "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
+ val, m->imsi);
+ if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+ printf("Failed to update SQN in database for IMSI %s\n",
+ m->imsi);
+ return -1;
+ }
+ return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
static int open_socket(const char *path)
{
struct sockaddr_un addr;
@@ -460,6 +602,11 @@
m = m->next;
}
+#ifdef CONFIG_SQLITE
+ if (!m)
+ m = db_get_milenage(imsi);
+#endif /* CONFIG_SQLITE */
+
return m;
}
@@ -577,6 +724,7 @@
size_t res_len;
int ret;
struct milenage_parameters *m;
+ int failed = 0;
m = get_milenage(imsi);
if (m) {
@@ -584,6 +732,9 @@
return;
res_len = EAP_AKA_RES_MAX_LEN;
inc_sqn(m->sqn);
+#ifdef CONFIG_SQLITE
+ db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
sqn_changes = 1;
printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
m->sqn[0], m->sqn[1], m->sqn[2],
@@ -601,7 +752,7 @@
memset(res, '2', EAP_AKA_RES_MAX_LEN);
res_len = EAP_AKA_RES_MAX_LEN;
#else /* AKA_USE_FIXED_TEST_VALUES */
- return;
+ failed = 1;
#endif /* AKA_USE_FIXED_TEST_VALUES */
}
@@ -611,6 +762,13 @@
if (ret < 0 || ret >= end - pos)
return;
pos += ret;
+ if (failed) {
+ ret = snprintf(pos, end - pos, "FAILURE");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ goto done;
+ }
pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
@@ -621,6 +779,7 @@
*pos++ = ' ';
pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
+done:
printf("Send: %s\n", reply);
if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
@@ -668,6 +827,9 @@
printf("AKA-AUTS: Re-synchronized: "
"SQN=%02x%02x%02x%02x%02x%02x\n",
sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+#ifdef CONFIG_SQLITE
+ db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
sqn_changes = 1;
}
}
@@ -734,6 +896,13 @@
close(serv_sock);
unlink(socket_path);
+
+#ifdef CONFIG_SQLITE
+ if (sqlite_db) {
+ sqlite3_close(sqlite_db);
+ sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
}
@@ -753,7 +922,7 @@
"usage:\n"
"hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
"[-m<milenage file>] \\\n"
- " [-i<IND len in bits>]\n"
+ " [-D<DB file>] [-i<IND len in bits>]\n"
"\n"
"options:\n"
" -h = show this usage help\n"
@@ -762,6 +931,7 @@
" (default: %s)\n"
" -g<triplet file> = path for GSM authentication triplets\n"
" -m<milenage file> = path for Milenage keys\n"
+ " -D<DB file> = path to SQLite database\n"
" -i<IND len in bits> = IND length for SQN (default: 5)\n",
default_socket_path);
}
@@ -771,6 +941,7 @@
{
int c;
char *gsm_triplet_file = NULL;
+ char *sqlite_db_file = NULL;
if (os_program_init())
return -1;
@@ -778,10 +949,18 @@
socket_path = default_socket_path;
for (;;) {
- c = getopt(argc, argv, "g:hi:m:s:u");
+ c = getopt(argc, argv, "D:g:hi:m:s:u");
if (c < 0)
break;
switch (c) {
+ case 'D':
+#ifdef CONFIG_SQLITE
+ sqlite_db_file = optarg;
+ break;
+#else /* CONFIG_SQLITE */
+ printf("No SQLite support included in the build\n");
+ return -1;
+#endif /* CONFIG_SQLITE */
case 'g':
gsm_triplet_file = optarg;
break;
@@ -810,6 +989,16 @@
}
}
+ if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
+ usage();
+ return -1;
+ }
+
+#ifdef CONFIG_SQLITE
+ if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
+ return -1;
+#endif /* CONFIG_SQLITE */
+
if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
return -1;
@@ -829,6 +1018,13 @@
for (;;)
process(serv_sock);
+#ifdef CONFIG_SQLITE
+ if (sqlite_db) {
+ sqlite3_close(sqlite_db);
+ sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
+
os_program_deinit();
return 0;
diff --git a/hostapd/hlr_auc_gw.txt b/hostapd/hlr_auc_gw.txt
new file mode 100644
index 0000000..097bbce
--- /dev/null
+++ b/hostapd/hlr_auc_gw.txt
@@ -0,0 +1,104 @@
+HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+
+hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
+database/authentication gateway interface to HLR/AuC. It could be
+replaced with an implementation of SS7 gateway to GSM/UMTS
+authentication center (HLR/AuC). hostapd will send SIM/AKA
+authentication queries over a UNIX domain socket to and external
+program, e.g., hlr_auc_gw.
+
+hlr_auc_gw can be configured with GSM and UMTS authentication data with
+text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
+hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
+dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
+GSM triplet data is used for a more static configuration (e.g., triplets
+extracted from a SIM card).
+
+Alternatively, hlr_auc_gw can be built with support for an SQLite
+database for more dynamic operations. This is enabled by adding
+"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
+clean; make hlr_auc_gw" in this directory).
+
+hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
+hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
+is configured with command line parameters:
+
+hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
+ [-D<DB file>] [-i<IND len in bits>]
+
+options:
+ -h = show this usage help
+ -u = update SQN in Milenage file on exit
+ -s<socket path> = path for UNIX domain socket
+ (default: /tmp/hlr_auc_gw.sock)
+ -g<triplet file> = path for GSM authentication triplets
+ -m<milenage file> = path for Milenage keys
+ -D<DB file> = path to SQLite database
+ -i<IND len in bits> = IND length for SQN (default: 5)
+
+
+The SQLite database can be initialized with sqlite, e.g., by running
+following commands in "sqlite3 /path/to/hlr_auc_gw.db":
+
+CREATE TABLE milenage(
+ imsi INTEGER PRIMARY KEY NOT NULL,
+ ki CHAR(32) NOT NULL,
+ opc CHAR(32) NOT NULL,
+ amf CHAR(4) NOT NULL,
+ sqn CHAR(12) NOT NULL
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+ 232010000000000,
+ '90dca4eda45b53cf0f12d7c9c3bc6a89',
+ 'cb9cccc4b9258e6dca4760379fb82581',
+ '61df',
+ '000000000000'
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+ 555444333222111,
+ '5122250214c33e723a5dd523fc145fc0',
+ '981d464c7c52eb6e5036234984ad0bcf',
+ 'c3ab',
+ '16f3b3f70fc1'
+);
+
+
+hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
+pseudonyms and reauth information into a SQLite database. This is
+configured with the db parameter within the eap_sim_db configuration
+option.
+
+
+"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
+Milenage parameters based on IMSI from the database. The database can be
+updated dynamically while hlr_auc_gw is running to add/remove/modify
+entries.
+
+
+Example configuration files for hostapd to operate as a RADIUS
+authentication server for EAP-SIM/AKA/AKA':
+
+hostapd.conf:
+
+driver=none
+radius_server_clients=hostapd.radius_clients
+eap_server=1
+eap_user_file=hostapd.eap_user
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
+eap_sim_aka_result_ind=1
+
+hostapd.radius_clients:
+
+0.0.0.0/0 radius
+
+hostapd.eap_user:
+
+"0"* AKA
+"1"* SIM
+"2"* AKA
+"3"* SIM
+"4"* AKA
+"5"* SIM
+"6"* AKA'
+"7"* AKA'
+"8"* AKA'
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index daa03d2..edbd772 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -84,6 +84,11 @@
# SSID to be used in IEEE 802.11 management frames
ssid=test
+# Alternative formats for configuring SSID
+# (double quoted string, hexdump, printf-escaped string)
+#ssid2="test"
+#ssid2=74657374
+#ssid2=P"hello\nthere"
# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
# Set as needed to indicate country in which device is operating.
@@ -196,6 +201,13 @@
# requests for broadcast SSID
ignore_broadcast_ssid=0
+# Additional vendor specfic elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#vendor_elements=dd0411223301
+
# TX queue parameters (EDCF / bursting)
# tx_queue_<queue name>_<param>
# queues: data0, data1, data2, data3, after_beacon, beacon
@@ -489,7 +501,7 @@
# else reserved (default)
#
# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
-# BeamformerÂ’s capability indicating the maximum value of the NUM_STS parameter
+# 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
# else reserved (default)
@@ -522,7 +534,7 @@
# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
# This field is an integer in the range of 0 to 7.
# The length defined by this field is equal to
-# 2 pow(13 + Maximum A-MPDU Length Exponent) –1 octets
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
#
# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
# Indicates whether or not the STA supports link adaptation using VHT variant
@@ -545,7 +557,21 @@
# 0 = Tx antenna pattern might change during the lifetime of an association
# 1 = Tx antenna pattern does not change during the lifetime of an association
#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
##### IEEE 802.1X-2004 related configuration ##################################
@@ -655,8 +681,10 @@
# This is a text string in implementation specific format. The example
# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
-# prefix.
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
# random value. It is configured as a 16-octet value in hex format. It can be
@@ -796,6 +824,12 @@
# to the bridge.
#vlan_tagged_interface=eth0
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
# Arbitrary RADIUS attributes can be added into Access-Request and
# Accounting-Request packets by specifying the contents of the attributes with
# the following configuration parameters. There can be multiple of these to
@@ -1311,7 +1345,7 @@
# Arbitrary number of Roaming Consortium OIs can be configured with each line
# adding a new OI to the list. The first three entries are available through
# Beacon and Probe Response frames. Any additional entry will be available only
-# through ANQP queries. Each OI is between 3 and 15 octets and is configured a
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
# a hexstring.
#roaming_consortium=021122
#roaming_consortium=2233445566
@@ -1325,6 +1359,124 @@
#venue_name=eng:Example venue
#venue_name=fin:Esimerkkipaikka
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+# 0 = Realm formatted in accordance with IETF RFC 4282
+# 1 = UTF-8 formatted character string that is not formatted in
+# accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+# 1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+# 1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+# 5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+# 10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+# (encoded as two hex digits)
+# Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+# 1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+# 1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
##### Multiple BSSID support ##################################################
#
# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 0c33d5b..27bea2a 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -71,6 +71,7 @@
" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
" wps_check_pin <PIN> verify PIN checksum\n"
" wps_pbc indicate button pushed to initiate PBC\n"
+" wps_cancel cancel the pending WPS operation\n"
#ifdef CONFIG_WPS_OOB
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
#endif /* CONFIG_WPS_OOB */
@@ -92,7 +93,12 @@
static struct wpa_ctrl *ctrl_conn;
static int hostapd_cli_quit = 0;
static int hostapd_cli_attached = 0;
-static const char *ctrl_iface_dir = "/var/run/hostapd";
+
+#ifndef CONFIG_CTRL_IFACE_DIR
+#define CONFIG_CTRL_IFACE_DIR "/var/run/hostapd"
+#endif /* CONFIG_CTRL_IFACE_DIR */
+static const char *ctrl_iface_dir = CONFIG_CTRL_IFACE_DIR;
+
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
static const char *action_file = NULL;
@@ -977,7 +983,7 @@
eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
- NULL, NULL, NULL);
+ NULL, NULL, NULL, NULL);
eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
eloop_run();
diff --git a/hostapd/main.c b/hostapd/main.c
index d8c2776..56f0002 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -166,14 +166,9 @@
if (hapd_iface == NULL)
goto fail;
- hapd_iface->reload_config = hostapd_reload_config;
- hapd_iface->config_read_cb = hostapd_config_read;
hapd_iface->config_fname = os_strdup(config_file);
if (hapd_iface->config_fname == NULL)
goto fail;
- hapd_iface->ctrl_iface_init = hostapd_ctrl_iface_init;
- hapd_iface->ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
- hapd_iface->for_each_interface = hostapd_for_each_interface;
conf = hostapd_config_read(hapd_iface->config_fname);
if (conf == NULL)
@@ -181,7 +176,7 @@
hapd_iface->conf = conf;
hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
goto fail;
@@ -248,13 +243,13 @@
}
params.bssid = b;
params.ifname = hapd->conf->iface;
- params.ssid = (const u8 *) hapd->conf->ssid.ssid;
+ params.ssid = hapd->conf->ssid.ssid;
params.ssid_len = hapd->conf->ssid.ssid_len;
params.test_socket = hapd->conf->test_socket;
params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
params.num_bridge = hapd->iface->num_bss;
- params.bridge = os_zalloc(hapd->iface->num_bss * sizeof(char *));
+ params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
if (params.bridge == NULL)
return -1;
for (i = 0; i < hapd->iface->num_bss; i++) {
@@ -284,21 +279,6 @@
}
-static void hostapd_interface_deinit_free(struct hostapd_iface *iface)
-{
- const struct wpa_driver_ops *driver;
- void *drv_priv;
- if (iface == NULL)
- return;
- driver = iface->bss[0]->driver;
- drv_priv = iface->bss[0]->drv_priv;
- hostapd_interface_deinit(iface);
- if (driver && driver->hapd_deinit && drv_priv)
- driver->hapd_deinit(drv_priv);
- hostapd_interface_free(iface);
-}
-
-
static struct hostapd_iface *
hostapd_interface_init(struct hapd_interfaces *interfaces,
const char *config_fname, int debug)
@@ -411,7 +391,7 @@
wpa_printf(MSG_ERROR, "No drivers enabled");
return -1;
}
- global.drv_priv = os_zalloc(global.drv_count * sizeof(void *));
+ global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
if (global.drv_priv == NULL)
return -1;
@@ -499,13 +479,15 @@
fprintf(stderr,
"\n"
"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
- "<configuration file(s)>\n"
+ "\\\n"
+ " [-g <global ctrl_iface>] <configuration file(s)>\n"
"\n"
"options:\n"
" -h show this usage\n"
" -d show more debug messages (-dd for even more)\n"
" -B run daemon in the background\n"
" -e entropy file\n"
+ " -g global control interface path\n"
" -P PID file\n"
" -K include key data in debug messages\n"
#ifdef CONFIG_DEBUG_FILE
@@ -527,6 +509,28 @@
}
+static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
+ const char *path)
+{
+ char *pos;
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = os_strdup(path);
+ if (interfaces->global_iface_path == NULL)
+ return -1;
+ pos = os_strrchr(interfaces->global_iface_path, '/');
+ if (pos == NULL) {
+ os_free(interfaces->global_iface_path);
+ interfaces->global_iface_path = NULL;
+ return -1;
+ }
+
+ *pos = '\0';
+ interfaces->global_iface_name = pos + 1;
+
+ return 0;
+}
+
+
int main(int argc, char *argv[])
{
struct hapd_interfaces interfaces;
@@ -540,8 +544,19 @@
if (os_program_init())
return -1;
+ os_memset(&interfaces, 0, sizeof(interfaces));
+ interfaces.reload_config = hostapd_reload_config;
+ interfaces.config_read_cb = hostapd_config_read;
+ interfaces.for_each_interface = hostapd_for_each_interface;
+ interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
+ interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+ interfaces.driver_init = hostapd_driver_init;
+ interfaces.global_iface_path = NULL;
+ interfaces.global_iface_name = NULL;
+ interfaces.global_ctrl_sock = -1;
+
for (;;) {
- c = getopt(argc, argv, "Bde:f:hKP:tv");
+ c = getopt(argc, argv, "Bde:f:hKP:tvg:");
if (c < 0)
break;
switch (c) {
@@ -576,6 +591,9 @@
show_version();
exit(1);
break;
+ case 'g':
+ hostapd_get_global_ctrl_iface(&interfaces, optarg);
+ break;
default:
usage();
@@ -583,7 +601,7 @@
}
}
- if (optind == argc)
+ if (optind == argc && interfaces.global_iface_path == NULL)
usage();
wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
@@ -592,11 +610,13 @@
wpa_debug_open_file(log_file);
interfaces.count = argc - optind;
- interfaces.iface = os_zalloc(interfaces.count *
- sizeof(struct hostapd_iface *));
- if (interfaces.iface == NULL) {
- wpa_printf(MSG_ERROR, "malloc failed");
- return -1;
+ if (interfaces.count) {
+ interfaces.iface = os_calloc(interfaces.count,
+ sizeof(struct hostapd_iface *));
+ if (interfaces.iface == NULL) {
+ wpa_printf(MSG_ERROR, "malloc failed");
+ return -1;
+ }
}
if (hostapd_global_init(&interfaces, entropy_file))
@@ -611,12 +631,15 @@
goto out;
}
+ hostapd_global_ctrl_iface_init(&interfaces);
+
if (hostapd_global_run(&interfaces, daemonize, pid_file))
goto out;
ret = 0;
out:
+ hostapd_global_ctrl_iface_deinit(&interfaces);
/* Deinitialize all interfaces */
for (i = 0; i < interfaces.count; i++)
hostapd_interface_deinit_free(interfaces.iface[i]);
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 2c3a6d9..7563b52 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -28,6 +28,8 @@
static void accounting_sta_get_id(struct hostapd_data *hapd,
struct sta_info *sta);
+static void accounting_sta_interim(struct hostapd_data *hapd,
+ struct sta_info *sta);
static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
@@ -40,7 +42,6 @@
size_t len;
int i;
struct wpabuf *b;
- struct hostapd_radius_attr *attr;
msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
radius_client_get_id(hapd->radius));
@@ -80,7 +81,17 @@
}
if (sta) {
+ /* Use 802.1X identity if available */
val = ieee802_1x_get_identity(sta->eapol_sm, &len);
+
+ /* Use RADIUS ACL identity if 802.1X provides no identity */
+ if (!val && sta->identity) {
+ val = (u8 *) sta->identity;
+ len = os_strlen(sta->identity);
+ }
+
+ /* Use STA MAC if neither 802.1X nor RADIUS ACL provided
+ * identity */
if (!val) {
os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
MAC2STR(sta->addr));
@@ -95,86 +106,11 @@
}
}
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_IP_ADDRESS) &&
- hapd->conf->own_ip_addr.af == AF_INET &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
- printf("Could not add NAS-IP-Address\n");
+ if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
+ msg) < 0)
goto fail;
- }
-
-#ifdef CONFIG_IPV6
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
- hapd->conf->own_ip_addr.af == AF_INET6 &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
- printf("Could not add NAS-IPv6-Address\n");
- goto fail;
- }
-#endif /* CONFIG_IPV6 */
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_IDENTIFIER) &&
- hapd->conf->nas_identifier &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
- (u8 *) hapd->conf->nas_identifier,
- os_strlen(hapd->conf->nas_identifier))) {
- printf("Could not add NAS-Identifier\n");
- goto fail;
- }
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_PORT) &&
- sta &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
- printf("Could not add NAS-Port\n");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_CALLED_STATION_ID) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Called-Station-Id\n");
- goto fail;
- }
if (sta) {
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
- MAC2STR(sta->addr));
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Calling-Station-Id\n");
- goto fail;
- }
-
- if (!hostapd_config_get_radius_attr(
- hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_NAS_PORT_TYPE) &&
- !radius_msg_add_attr_int32(
- msg, RADIUS_ATTR_NAS_PORT_TYPE,
- RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
- printf("Could not add NAS-Port-Type\n");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
- radius_sta_rate(hapd, sta) / 2,
- (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
- radius_mode_txt(hapd));
- if (!hostapd_config_get_radius_attr(
- hapd->conf->radius_acct_req_attr,
- RADIUS_ATTR_CONNECT_INFO) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Connect-Info\n");
- goto fail;
- }
-
for (i = 0; ; i++) {
val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
i);
@@ -196,15 +132,13 @@
wpa_printf(MSG_ERROR, "Could not add CUI");
goto fail;
}
- }
- for (attr = hapd->conf->radius_acct_req_attr; attr; attr = attr->next)
- {
- if (!radius_msg_add_attr(msg, attr->type,
- wpabuf_head(attr->val),
- wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
+ if (!b && sta->radius_cui &&
+ !radius_msg_add_attr(msg,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ (u8 *) sta->radius_cui,
+ os_strlen(sta->radius_cui))) {
+ wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
goto fail;
}
}
@@ -415,7 +349,8 @@
* @hapd: hostapd BSS data
* @sta: The station
*/
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
+static void accounting_sta_interim(struct hostapd_data *hapd,
+ struct sta_info *sta)
{
if (sta->acct_session_started)
accounting_sta_report(hapd, sta, 0);
diff --git a/src/ap/accounting.h b/src/ap/accounting.h
index 797e24d..9d13d01 100644
--- a/src/ap/accounting.h
+++ b/src/ap/accounting.h
@@ -9,7 +9,6 @@
#ifndef ACCOUNTING_H
#define ACCOUNTING_H
-void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
#ifdef CONFIG_NO_ACCOUNTING
static inline void accounting_sta_start(struct hostapd_data *hapd,
struct sta_info *sta)
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 2c633d9..31e1c19 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -104,9 +104,9 @@
const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
- { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
- { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
const struct hostapd_tx_queue_params txq_bk =
{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
const struct hostapd_tx_queue_params txq_be =
@@ -498,10 +498,23 @@
os_free(conf->roaming_consortium);
os_free(conf->venue_name);
+ os_free(conf->nai_realm_data);
+ os_free(conf->network_auth_type);
+ os_free(conf->anqp_3gpp_cell_net);
+ os_free(conf->domain_name);
#ifdef CONFIG_RADIUS_TEST
os_free(conf->dump_msk_file);
#endif /* CONFIG_RADIUS_TEST */
+
+#ifdef CONFIG_HS20
+ os_free(conf->hs20_oper_friendly_name);
+ os_free(conf->hs20_wan_metrics);
+ os_free(conf->hs20_connection_capability);
+ os_free(conf->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+ wpabuf_free(conf->vendor_elements);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ca4fe58..f5e4a6a 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -12,6 +12,7 @@
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_common.h"
#include "wps/wps.h"
#define MAX_STA_COUNT 2007
@@ -48,7 +49,7 @@
} secpolicy;
struct hostapd_ssid {
- char ssid[HOSTAPD_MAX_SSID_LEN + 1];
+ u8 ssid[HOSTAPD_MAX_SSID_LEN];
size_t ssid_len;
int ssid_set;
@@ -65,6 +66,10 @@
#define DYNAMIC_VLAN_OPTIONAL 1
#define DYNAMIC_VLAN_REQUIRED 2
int dynamic_vlan;
+#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0
+#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
+#define DYNAMIC_VLAN_NAMING_END 2
+ int vlan_naming;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
char *vlan_tagged_interface;
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -132,14 +137,6 @@
int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
};
-struct hostapd_wmm_ac_params {
- int cwmin;
- int cwmax;
- int aifs;
- int txop_limit; /* in units of 32us */
- int admission_control_mandatory;
-};
-
#define MAX_ROAMING_CONSORTIUM_LEN 15
@@ -148,12 +145,29 @@
u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
};
-struct hostapd_venue_name {
+struct hostapd_lang_string {
u8 lang[3];
u8 name_len;
u8 name[252];
};
+#define MAX_NAI_REALMS 10
+#define MAX_NAI_REALMLEN 255
+#define MAX_NAI_EAP_METHODS 5
+#define MAX_NAI_AUTH_TYPES 4
+struct hostapd_nai_realm_data {
+ u8 encoding;
+ char realm_buf[MAX_NAI_REALMLEN + 1];
+ char *realm[MAX_NAI_REALMS];
+ u8 eap_method_count;
+ struct hostapd_nai_realm_eap {
+ u8 eap_method;
+ u8 num_auths;
+ u8 auth_id[MAX_NAI_AUTH_TYPES];
+ u8 auth_val[MAX_NAI_AUTH_TYPES];
+ } eap_method[MAX_NAI_EAP_METHODS];
+};
+
/**
* struct hostapd_bss_config - Per-BSS configuration
*/
@@ -389,16 +403,49 @@
/* IEEE 802.11u - Venue Name duples */
unsigned int venue_name_count;
- struct hostapd_venue_name *venue_name;
+ struct hostapd_lang_string *venue_name;
+
+ /* IEEE 802.11u - Network Authentication Type */
+ u8 *network_auth_type;
+ size_t network_auth_type_len;
+
+ /* IEEE 802.11u - IP Address Type Availability */
+ u8 ipaddr_type_availability;
+ u8 ipaddr_type_configured;
+
+ /* IEEE 802.11u - 3GPP Cellular Network */
+ u8 *anqp_3gpp_cell_net;
+ size_t anqp_3gpp_cell_net_len;
+
+ /* IEEE 802.11u - Domain Name */
+ u8 *domain_name;
+ size_t domain_name_len;
+
+ unsigned int nai_realm_count;
+ struct hostapd_nai_realm_data *nai_realm_data;
u16 gas_comeback_delay;
int gas_frag_limit;
+#ifdef CONFIG_HS20
+ int hs20;
+ int disable_dgaf;
+ unsigned int hs20_oper_friendly_name_count;
+ struct hostapd_lang_string *hs20_oper_friendly_name;
+ u8 *hs20_wan_metrics;
+ u8 *hs20_connection_capability;
+ size_t hs20_connection_capability_len;
+ u8 *hs20_operating_class;
+ u8 hs20_operating_class_len;
+#endif /* CONFIG_HS20 */
+
u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
#ifdef CONFIG_RADIUS_TEST
char *dump_msk_file;
#endif /* CONFIG_RADIUS_TEST */
+
+ struct wpabuf *vendor_elements;
};
@@ -455,7 +502,9 @@
int require_ht;
u32 vht_capab;
int ieee80211ac;
+ int require_vht;
u8 vht_oper_chwidth;
+ u8 vht_oper_centr_freq_seg0_idx;
};
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 859b529..02da25b 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -12,11 +12,13 @@
#include "drivers/driver.h"
#include "common/ieee802_11_defs.h"
#include "wps/wps.h"
+#include "p2p/p2p.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
#include "ap_config.h"
#include "p2p_hostapd.h"
+#include "hs20.h"
#include "ap_drv_ops.h"
@@ -147,6 +149,30 @@
}
#endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_WIFI_DISPLAY
+ if (hapd->p2p_group) {
+ struct wpabuf *a;
+ a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
+ if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+ wpabuf_put_buf(assocresp, a);
+ wpabuf_free(a);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_HS20
+ pos = buf;
+ pos = hostapd_eid_hs20_indication(hapd, pos);
+ if (pos != buf) {
+ if (wpabuf_resize(&beacon, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(beacon, buf, pos - buf);
+
+ if (wpabuf_resize(&proberesp, pos - buf) != 0)
+ goto fail;
+ wpabuf_put_data(proberesp, buf, pos - buf);
+ }
+#endif /* CONFIG_HS20 */
+
*beacon_ret = beacon;
*proberesp_ret = proberesp;
*assocresp_ret = assocresp;
@@ -586,6 +612,16 @@
}
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
+ const u8 *peer, u8 *buf, u16 *buf_len)
+{
+ if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
+ return 0;
+ return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
+ buf_len);
+}
+
+
int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
unsigned int wait, const u8 *dst, const u8 *data,
size_t len)
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 169c91b..9c53b99 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -101,6 +101,10 @@
#include "drivers/driver.h"
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
+ enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len);
+
static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
int enabled)
{
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index 933b158..18090ca 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -251,23 +251,9 @@
ap->ssid_len = len;
}
- os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
- len = 0;
- if (elems->supp_rates) {
- len = elems->supp_rates_len;
- if (len > WLAN_SUPP_RATES_MAX)
- len = WLAN_SUPP_RATES_MAX;
- os_memcpy(ap->supported_rates, elems->supp_rates, len);
- }
- if (elems->ext_supp_rates) {
- int len2;
- if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
- len2 = WLAN_SUPP_RATES_MAX - len;
- else
- len2 = elems->ext_supp_rates_len;
- os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
- len2);
- }
+ merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
ap->wpa = elems->wpa_ie != NULL;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0f29ccd..f761bf5 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -33,6 +33,7 @@
#include "p2p_hostapd.h"
#include "ap_drv_ops.h"
#include "beacon.h"
+#include "hs20.h"
#ifdef NEED_AP_MLME
@@ -205,6 +206,8 @@
if (hapd->p2p_probe_resp_ie)
buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
#endif /* CONFIG_P2P */
+ if (hapd->conf->vendor_elements)
+ buflen += wpabuf_len(hapd->conf->vendor_elements);
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -292,6 +295,16 @@
pos = hostapd_eid_p2p_manage(hapd, pos);
#endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_HS20
+ pos = hostapd_eid_hs20_indication(hapd, pos);
+#endif /* CONFIG_HS20 */
+
+ if (hapd->conf->vendor_elements) {
+ os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
+ wpabuf_len(hapd->conf->vendor_elements));
+ pos += wpabuf_len(hapd->conf->vendor_elements);
+ }
+
*resp_len = pos - (u8 *) resp;
return (u8 *) resp;
}
@@ -523,6 +536,8 @@
if (hapd->p2p_beacon_ie)
tail_len += wpabuf_len(hapd->p2p_beacon_ie);
#endif /* CONFIG_P2P */
+ if (hapd->conf->vendor_elements)
+ tail_len += wpabuf_len(hapd->conf->vendor_elements);
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -629,6 +644,16 @@
tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
#endif /* CONFIG_P2P_MANAGER */
+#ifdef CONFIG_HS20
+ tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+#endif /* CONFIG_HS20 */
+
+ if (hapd->conf->vendor_elements) {
+ os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
+ wpabuf_len(hapd->conf->vendor_elements));
+ tailpos += wpabuf_len(hapd->conf->vendor_elements);
+ }
+
tail_len = tailpos > tail ? tailpos - tail : 0;
resp = hostapd_probe_resp_offloads(hapd, &resp_len);
@@ -643,8 +668,8 @@
params.proberesp_len = resp_len;
params.dtim_period = hapd->conf->dtim_period;
params.beacon_int = hapd->iconf->beacon_int;
- params.basic_rates = hapd->iconf->basic_rates;
- params.ssid = (u8 *) hapd->conf->ssid.ssid;
+ 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->rsn_pairwise ?
hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
@@ -694,6 +719,9 @@
params.hessid = hapd->conf->hessid;
params.access_network_type = hapd->conf->access_network_type;
params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_HS20
+ params.disable_dgaf = hapd->conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
if (hostapd_drv_set_ap(hapd, ¶ms))
wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index cf06a4f..23fa241 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -16,6 +16,7 @@
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
+#include "wnm_ap.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
@@ -37,7 +38,12 @@
struct ieee802_11_elems elems;
const u8 *ie;
size_t ielen;
+#ifdef CONFIG_IEEE80211R
+ u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+ u8 *p = buf;
+#endif /* CONFIG_IEEE80211R */
u16 reason = WLAN_REASON_UNSPECIFIED;
+ u16 status = WLAN_STATUS_SUCCESS;
if (addr == NULL) {
/*
@@ -146,27 +152,85 @@
return -1;
}
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
- ie, ielen, NULL, 0);
+ 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_hexdump(MSG_DEBUG, "IE", ie, ielen);
- if (res == WPA_INVALID_GROUP)
+ if (res == WPA_INVALID_GROUP) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_PAIRWISE)
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ } else if (res == WPA_INVALID_PAIRWISE) {
reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
- else if (res == WPA_INVALID_AKMP)
+ status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ } else if (res == WPA_INVALID_AKMP) {
reason = WLAN_REASON_AKMP_NOT_VALID;
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ }
#ifdef CONFIG_IEEE80211W
- else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+ else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
reason = WLAN_REASON_INVALID_IE;
- else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+ status = WLAN_STATUS_INVALID_IE;
+ } else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+ status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ }
#endif /* CONFIG_IEEE80211W */
- else
+ else {
reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
+ }
goto fail;
}
+#ifdef CONFIG_IEEE80211W
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ sta->sa_query_count > 0)
+ ap_check_sa_query_timeout(hapd, sta);
+ if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+ (sta->auth_alg != WLAN_AUTH_FT)) {
+ /*
+ * STA has already been associated with MFP and SA
+ * Query timeout has not been reached. Reject the
+ * association attempt temporarily and start SA Query,
+ * if one is not pending.
+ */
+
+ 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;
+ }
+
+ if (wpa_auth_uses_mfp(sta->wpa_sm))
+ sta->flags |= WLAN_STA_MFP;
+ else
+ sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+ if (sta->auth_alg == WLAN_AUTH_FT) {
+ status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
+ req_ies_len);
+ if (status != WLAN_STATUS_SUCCESS) {
+ if (status == WLAN_STATUS_INVALID_PMKID)
+ reason = WLAN_REASON_INVALID_IE;
+ if (status == WLAN_STATUS_INVALID_MDIE)
+ reason = WLAN_REASON_INVALID_IE;
+ if (status == WLAN_STATUS_INVALID_FTIE)
+ reason = WLAN_REASON_INVALID_IE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_IEEE80211R */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
@@ -178,6 +242,7 @@
#ifdef CONFIG_WPS_STRICT
if (wps && wps_validate_assoc_req(wps) < 0) {
reason = WLAN_REASON_INVALID_IE;
+ status = WLAN_STATUS_INVALID_IE;
wpabuf_free(wps);
goto fail;
}
@@ -198,9 +263,24 @@
skip_wpa_check:
#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211R
+ p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
+ sta->auth_alg, req_ies, req_ies_len);
+
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#else /* CONFIG_IEEE80211R */
+ /* Keep compiler silent about unused variables */
+ if (status) {
+ }
+#endif /* CONFIG_IEEE80211R */
+
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
- wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+
+ if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+ else
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
hostapd_new_assoc_sta(hapd, sta, !new_assoc);
@@ -216,6 +296,9 @@
return 0;
fail:
+#ifdef CONFIG_IEEE80211R
+ hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#endif /* CONFIG_IEEE80211R */
hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
ap_free_sta(hapd, sta);
return -1;
@@ -326,6 +409,110 @@
#ifdef HOSTAPD
+#ifdef CONFIG_IEEE80211R
+static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
+ const u8 *bssid,
+ u16 auth_transaction, u16 status,
+ const u8 *ies, size_t ies_len)
+{
+ struct hostapd_data *hapd = ctx;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, dst);
+ if (sta == NULL)
+ return;
+
+ hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+ sta->flags |= WLAN_STA_AUTH;
+
+ hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void hostapd_notif_auth(struct hostapd_data *hapd,
+ struct auth_info *rx_auth)
+{
+ struct sta_info *sta;
+ u16 status = WLAN_STATUS_SUCCESS;
+ u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+ size_t resp_ies_len = 0;
+
+ sta = ap_get_sta(hapd, rx_auth->peer);
+ if (!sta) {
+ sta = ap_sta_add(hapd, rx_auth->peer);
+ if (sta == NULL) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+ sta->flags &= ~WLAN_STA_PREAUTH;
+ ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+#ifdef CONFIG_IEEE80211R
+ if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
+ sta->auth_alg = WLAN_AUTH_FT;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+ "state machine");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
+ rx_auth->auth_transaction, rx_auth->ies,
+ rx_auth->ies_len,
+ hostapd_notify_auth_ft_finish, hapd);
+ return;
+ }
+#endif /* CONFIG_IEEE80211R */
+fail:
+ hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
+ status, resp_ies, resp_ies_len);
+}
+
+
+static void hostapd_action_rx(struct hostapd_data *hapd,
+ struct rx_action *action)
+{
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
+ action->category, (int) action->len);
+
+ sta = ap_get_sta(hapd, action->sa);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+ return;
+ }
+#ifdef CONFIG_IEEE80211R
+ if (action->category == WLAN_ACTION_FT) {
+ wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
+ __func__, (int) action->len);
+ wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
+ }
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
+ wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
+ __func__, (int) action->len);
+ ieee802_11_sa_query_action(hapd, action->sa,
+ *(action->data + 1),
+ action->data + 2);
+ }
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211V
+ if (action->category == WLAN_ACTION_WNM) {
+ wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
+ __func__, (int) action->len);
+ ieee802_11_rx_wnm_action_ap(hapd, action);
+ }
+#endif /* CONFIG_IEEE80211V */
+}
+
+
#ifdef NEED_AP_MLME
#define HAPD_BROADCAST ((struct hostapd_data *) -1)
@@ -505,7 +692,7 @@
#ifndef CONFIG_NO_STDOUT_DEBUG
int level = MSG_DEBUG;
- if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+ if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
data->rx_mgmt.frame_len >= 24) {
const struct ieee80211_hdr *hdr;
u16 fc;
@@ -610,14 +797,18 @@
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
-#ifdef NEED_AP_MLME
case EVENT_RX_ACTION:
if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
data->rx_action.bssid == NULL)
break;
+#ifdef NEED_AP_MLME
hostapd_rx_action(hapd, &data->rx_action);
- break;
#endif /* NEED_AP_MLME */
+ hostapd_action_rx(hapd, &data->rx_action);
+ break;
+ case EVENT_AUTH:
+ hostapd_notif_auth(hapd, &data->auth);
+ break;
case EVENT_CH_SWITCH:
if (!data)
break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index 2177b02..53e6cbb 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -128,6 +128,31 @@
}
+static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ u8 *len;
+
+ len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+ if (hapd->conf->hs20_oper_friendly_name)
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ if (hapd->conf->hs20_wan_metrics)
+ wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+ if (hapd->conf->hs20_connection_capability)
+ wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+ if (hapd->conf->nai_realm_data)
+ wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+ if (hapd->conf->hs20_operating_class)
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+ gas_anqp_set_element_len(buf, len);
+}
+
+
static void anqp_add_capab_list(struct hostapd_data *hapd,
struct wpabuf *buf)
{
@@ -137,8 +162,19 @@
wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
if (hapd->conf->venue_name)
wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+ if (hapd->conf->network_auth_type)
+ wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
if (hapd->conf->roaming_consortium)
wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+ if (hapd->conf->ipaddr_type_configured)
+ wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+ if (hapd->conf->nai_realm_data)
+ wpabuf_put_le16(buf, ANQP_NAI_REALM);
+ if (hapd->conf->anqp_3gpp_cell_net)
+ wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+ if (hapd->conf->domain_name)
+ wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+ anqp_add_hs_capab_list(hapd, buf);
gas_anqp_set_element_len(buf, len);
}
@@ -152,7 +188,7 @@
wpabuf_put_u8(buf, hapd->conf->venue_group);
wpabuf_put_u8(buf, hapd->conf->venue_type);
for (i = 0; i < hapd->conf->venue_name_count; i++) {
- struct hostapd_venue_name *vn;
+ struct hostapd_lang_string *vn;
vn = &hapd->conf->venue_name[i];
wpabuf_put_u8(buf, 3 + vn->name_len);
wpabuf_put_data(buf, vn->lang, 3);
@@ -163,6 +199,18 @@
}
+static void anqp_add_network_auth_type(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->network_auth_type) {
+ wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
+ wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
+ wpabuf_put_data(buf, hapd->conf->network_auth_type,
+ hapd->conf->network_auth_type_len);
+ }
+}
+
+
static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
struct wpabuf *buf)
{
@@ -180,10 +228,283 @@
}
+static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->ipaddr_type_configured) {
+ wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+ wpabuf_put_le16(buf, 1);
+ wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
+ }
+}
+
+
+static void anqp_add_nai_realm_eap(struct wpabuf *buf,
+ struct hostapd_nai_realm_data *realm)
+{
+ unsigned int i, j;
+
+ wpabuf_put_u8(buf, realm->eap_method_count);
+
+ for (i = 0; i < realm->eap_method_count; i++) {
+ struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
+ wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
+ wpabuf_put_u8(buf, eap->eap_method);
+ wpabuf_put_u8(buf, eap->num_auths);
+ for (j = 0; j < eap->num_auths; j++) {
+ wpabuf_put_u8(buf, eap->auth_id[j]);
+ wpabuf_put_u8(buf, 1);
+ wpabuf_put_u8(buf, eap->auth_val[j]);
+ }
+ }
+}
+
+
+static void anqp_add_nai_realm_data(struct wpabuf *buf,
+ struct hostapd_nai_realm_data *realm,
+ unsigned int realm_idx)
+{
+ u8 *realm_data_len;
+
+ wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
+ (int) os_strlen(realm->realm[realm_idx]));
+ realm_data_len = wpabuf_put(buf, 2);
+ wpabuf_put_u8(buf, realm->encoding);
+ wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
+ wpabuf_put_str(buf, realm->realm[realm_idx]);
+ anqp_add_nai_realm_eap(buf, realm);
+ gas_anqp_set_element_len(buf, realm_data_len);
+}
+
+
+static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
+ struct wpabuf *buf,
+ const u8 *home_realm,
+ size_t home_realm_len)
+{
+ unsigned int i, j, k;
+ u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
+ struct hostapd_nai_realm_data *realm;
+ const u8 *pos, *realm_name, *end;
+ struct {
+ unsigned int realm_data_idx;
+ unsigned int realm_idx;
+ } matches[10];
+
+ pos = home_realm;
+ end = pos + home_realm_len;
+ if (pos + 1 > end) {
+ wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
+ home_realm, home_realm_len);
+ return -1;
+ }
+ num_realms = *pos++;
+
+ for (i = 0; i < num_realms && num_matching < 10; i++) {
+ if (pos + 2 > end) {
+ wpa_hexdump(MSG_DEBUG,
+ "Truncated NAI Home Realm Query",
+ home_realm, home_realm_len);
+ return -1;
+ }
+ encoding = *pos++;
+ realm_len = *pos++;
+ if (pos + realm_len > end) {
+ wpa_hexdump(MSG_DEBUG,
+ "Truncated NAI Home Realm Query",
+ home_realm, home_realm_len);
+ return -1;
+ }
+ realm_name = pos;
+ for (j = 0; j < hapd->conf->nai_realm_count &&
+ num_matching < 10; j++) {
+ const u8 *rpos, *rend;
+ realm = &hapd->conf->nai_realm_data[j];
+ if (encoding != realm->encoding)
+ continue;
+
+ rpos = realm_name;
+ while (rpos < realm_name + realm_len &&
+ num_matching < 10) {
+ for (rend = rpos;
+ rend < realm_name + realm_len; rend++) {
+ if (*rend == ';')
+ break;
+ }
+ for (k = 0; k < MAX_NAI_REALMS &&
+ realm->realm[k] &&
+ num_matching < 10; k++) {
+ if ((int) os_strlen(realm->realm[k]) !=
+ rend - rpos ||
+ os_strncmp((char *) rpos,
+ realm->realm[k],
+ rend - rpos) != 0)
+ continue;
+ matches[num_matching].realm_data_idx =
+ j;
+ matches[num_matching].realm_idx = k;
+ num_matching++;
+ }
+ rpos = rend + 1;
+ }
+ }
+ pos += realm_len;
+ }
+
+ realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+ wpabuf_put_le16(buf, num_matching);
+
+ /*
+ * There are two ways to format. 1. each realm in a NAI Realm Data unit
+ * 2. all realms that share the same EAP methods in a NAI Realm Data
+ * unit. The first format is likely to be bigger in size than the
+ * second, but may be easier to parse and process by the receiver.
+ */
+ for (i = 0; i < num_matching; i++) {
+ wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
+ matches[i].realm_data_idx, matches[i].realm_idx);
+ realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
+ anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
+ }
+ gas_anqp_set_element_len(buf, realm_list_len);
+ return 0;
+}
+
+
+static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
+ const u8 *home_realm, size_t home_realm_len,
+ int nai_realm, int nai_home_realm)
+{
+ if (nai_realm && hapd->conf->nai_realm_data) {
+ u8 *len;
+ unsigned int i, j;
+ len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+ wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
+ for (i = 0; i < hapd->conf->nai_realm_count; i++) {
+ u8 *realm_data_len, *realm_len;
+ struct hostapd_nai_realm_data *realm;
+
+ realm = &hapd->conf->nai_realm_data[i];
+ realm_data_len = wpabuf_put(buf, 2);
+ wpabuf_put_u8(buf, realm->encoding);
+ realm_len = wpabuf_put(buf, 1);
+ for (j = 0; realm->realm[j]; j++) {
+ if (j > 0)
+ wpabuf_put_u8(buf, ';');
+ wpabuf_put_str(buf, realm->realm[j]);
+ }
+ *realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
+ anqp_add_nai_realm_eap(buf, realm);
+ gas_anqp_set_element_len(buf, realm_data_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ } else if (nai_home_realm && hapd->conf->nai_realm_data) {
+ hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
+ home_realm_len);
+ }
+}
+
+
+static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->anqp_3gpp_cell_net) {
+ wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+ wpabuf_put_le16(buf,
+ hapd->conf->anqp_3gpp_cell_net_len);
+ wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
+ hapd->conf->anqp_3gpp_cell_net_len);
+ }
+}
+
+
+static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+ if (hapd->conf->domain_name) {
+ wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+ wpabuf_put_le16(buf, hapd->conf->domain_name_len);
+ wpabuf_put_data(buf, hapd->conf->domain_name,
+ hapd->conf->domain_name_len);
+ }
+}
+
+
+static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_oper_friendly_name) {
+ u8 *len;
+ unsigned int i;
+ len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
+ {
+ struct hostapd_lang_string *vn;
+ vn = &hapd->conf->hs20_oper_friendly_name[i];
+ wpabuf_put_u8(buf, 3 + vn->name_len);
+ wpabuf_put_data(buf, vn->lang, 3);
+ wpabuf_put_data(buf, vn->name, vn->name_len);
+ }
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_wan_metrics(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_wan_metrics) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_connection_capability(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_connection_capability) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
+ hapd->conf->hs20_connection_capability_len);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
+static void anqp_add_operating_class(struct hostapd_data *hapd,
+ struct wpabuf *buf)
+{
+ if (hapd->conf->hs20_operating_class) {
+ u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+ wpabuf_put_be24(buf, OUI_WFA);
+ wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+ wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+ wpabuf_put_u8(buf, 0); /* Reserved */
+ wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
+ hapd->conf->hs20_operating_class_len);
+ gas_anqp_set_element_len(buf, len);
+ }
+}
+
+
static struct wpabuf *
gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
unsigned int request,
- struct gas_dialog_info *di)
+ struct gas_dialog_info *di,
+ const u8 *home_realm, size_t home_realm_len)
{
struct wpabuf *buf;
@@ -195,8 +516,31 @@
anqp_add_capab_list(hapd, buf);
if (request & ANQP_REQ_VENUE_NAME)
anqp_add_venue_name(hapd, buf);
+ if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
+ anqp_add_network_auth_type(hapd, buf);
if (request & ANQP_REQ_ROAMING_CONSORTIUM)
anqp_add_roaming_consortium(hapd, buf);
+ if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
+ anqp_add_ip_addr_type_availability(hapd, buf);
+ if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
+ anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
+ request & ANQP_REQ_NAI_REALM,
+ request & ANQP_REQ_NAI_HOME_REALM);
+ if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
+ anqp_add_3gpp_cellular_network(hapd, buf);
+ if (request & ANQP_REQ_DOMAIN_NAME)
+ anqp_add_domain_name(hapd, buf);
+
+ if (request & ANQP_REQ_HS_CAPABILITY_LIST)
+ anqp_add_hs_capab_list(hapd, buf);
+ if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
+ anqp_add_operator_friendly_name(hapd, buf);
+ if (request & ANQP_REQ_WAN_METRICS)
+ anqp_add_wan_metrics(hapd, buf);
+ if (request & ANQP_REQ_CONNECTION_CAPABILITY)
+ anqp_add_connection_capability(hapd, buf);
+ if (request & ANQP_REQ_OPERATING_CLASS)
+ anqp_add_operating_class(hapd, buf);
return buf;
}
@@ -216,8 +560,8 @@
struct anqp_query_info {
unsigned int request;
unsigned int remote_request;
- const void *param;
- u32 param_arg;
+ const u8 *home_realm_query;
+ size_t home_realm_query_len;
u16 remote_delay;
};
@@ -252,10 +596,37 @@
set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
hapd->conf->venue_name != NULL, 0, 0, qi);
break;
+ case ANQP_NETWORK_AUTH_TYPE:
+ set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
+ hapd->conf->network_auth_type != NULL,
+ 0, 0, qi);
+ break;
case ANQP_ROAMING_CONSORTIUM:
set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
hapd->conf->roaming_consortium != NULL, 0, 0, qi);
break;
+ case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+ set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
+ "IP Addr Type Availability",
+ hapd->conf->ipaddr_type_configured,
+ 0, 0, qi);
+ break;
+ case ANQP_NAI_REALM:
+ set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
+ hapd->conf->nai_realm_data != NULL,
+ 0, 0, qi);
+ break;
+ case ANQP_3GPP_CELLULAR_NETWORK:
+ set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
+ "3GPP Cellular Network",
+ hapd->conf->anqp_3gpp_cell_net != NULL,
+ 0, 0, qi);
+ break;
+ case ANQP_DOMAIN_NAME:
+ set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
+ hapd->conf->domain_name != NULL,
+ 0, 0, qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
info_id);
@@ -278,13 +649,122 @@
}
+static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
+ struct anqp_query_info *qi)
+{
+ switch (subtype) {
+ case HS20_STYPE_CAPABILITY_LIST:
+ set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
+ 1, 0, 0, qi);
+ break;
+ case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+ set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
+ "Operator Friendly Name",
+ hapd->conf->hs20_oper_friendly_name != NULL,
+ 0, 0, qi);
+ break;
+ case HS20_STYPE_WAN_METRICS:
+ set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
+ hapd->conf->hs20_wan_metrics != NULL,
+ 0, 0, qi);
+ break;
+ case HS20_STYPE_CONNECTION_CAPABILITY:
+ set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
+ "Connection Capability",
+ hapd->conf->hs20_connection_capability != NULL,
+ 0, 0, qi);
+ break;
+ case HS20_STYPE_OPERATING_CLASS:
+ set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
+ hapd->conf->hs20_operating_class != NULL,
+ 0, 0, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
+ subtype);
+ break;
+ }
+}
+
+
+static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ qi->request |= ANQP_REQ_NAI_HOME_REALM;
+ qi->home_realm_query = pos;
+ qi->home_realm_query_len = end - pos;
+ if (hapd->conf->nai_realm_data != NULL) {
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
+ "(local)");
+ } else {
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
+ "available");
+ }
+}
+
+
+static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
+ const u8 *pos, const u8 *end,
+ struct anqp_query_info *qi)
+{
+ u32 oui;
+ u8 subtype;
+
+ if (pos + 4 > end) {
+ wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
+ "Query element");
+ return;
+ }
+
+ oui = WPA_GET_BE24(pos);
+ pos += 3;
+ if (oui != OUI_WFA) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
+ oui);
+ return;
+ }
+
+ if (*pos != HS20_ANQP_OUI_TYPE) {
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
+ *pos);
+ return;
+ }
+ pos++;
+
+ if (pos + 1 >= end)
+ return;
+
+ subtype = *pos++;
+ pos++; /* Reserved */
+ switch (subtype) {
+ case HS20_STYPE_QUERY_LIST:
+ wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
+ while (pos < end) {
+ rx_anqp_hs_query_list(hapd, *pos, qi);
+ pos++;
+ }
+ break;
+ case HS20_STYPE_NAI_HOME_REALM_QUERY:
+ rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
+ "%u", subtype);
+ break;
+ }
+}
+
+
static void gas_serv_req_local_processing(struct hostapd_data *hapd,
const u8 *sa, u8 dialog_token,
struct anqp_query_info *qi)
{
struct wpabuf *buf, *tx_buf;
- buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL);
+ buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+ qi->home_realm_query,
+ qi->home_realm_query_len);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
buf);
if (!buf)
@@ -419,6 +899,9 @@
case ANQP_QUERY_LIST:
rx_anqp_query_list(hapd, pos, pos + elen, &qi);
break;
+ case ANQP_VENDOR_SPECIFIC:
+ rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
+ break;
default:
wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
"Request element %u", info_id);
@@ -442,7 +925,7 @@
if (dialog->sd_resp == NULL) {
buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested,
- dialog);
+ dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf);
if (!buf)
@@ -571,7 +1054,7 @@
buf = gas_serv_build_gas_resp_payload(hapd,
dialog->all_requested,
- dialog);
+ dialog, NULL, 0);
wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
buf);
if (!buf)
diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
index 0e2eaf6..4213cf6 100644
--- a/src/ap/gas_serv.h
+++ b/src/ap/gas_serv.h
@@ -13,8 +13,30 @@
(1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
#define ANQP_REQ_VENUE_NAME \
(1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_NETWORK_AUTH_TYPE \
+ (1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
#define ANQP_REQ_ROAMING_CONSORTIUM \
(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
+ (1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_NAI_REALM \
+ (1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
+#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
+ (1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_DOMAIN_NAME \
+ (1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_HS_CAPABILITY_LIST \
+ (0x10000 << HS20_STYPE_CAPABILITY_LIST)
+#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
+ (0x10000 << HS20_STYPE_OPERATOR_FRIENDLY_NAME)
+#define ANQP_REQ_WAN_METRICS \
+ (0x10000 << HS20_STYPE_WAN_METRICS)
+#define ANQP_REQ_CONNECTION_CAPABILITY \
+ (0x10000 << HS20_STYPE_CONNECTION_CAPABILITY)
+#define ANQP_REQ_NAI_HOME_REALM \
+ (0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
+#define ANQP_REQ_OPERATING_CLASS \
+ (0x10000 << HS20_STYPE_OPERATING_CLASS)
/* To account for latencies between hostapd and external ANQP processor */
#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 22c5e65..3429258 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -39,6 +39,7 @@
static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
extern int wpa_debug_level;
+extern struct wpa_driver_ops *wpa_drivers[];
int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
@@ -98,7 +99,7 @@
hostapd_update_wps(hapd);
if (hapd->conf->ssid.ssid_set &&
- hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
+ hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
hapd->conf->ssid.ssid_len)) {
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
/* try to continue */
@@ -113,9 +114,10 @@
struct hostapd_config *newconf, *oldconf;
size_t j;
- if (iface->config_read_cb == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->config_read_cb == NULL)
return -1;
- newconf = iface->config_read_cb(iface->config_fname);
+ newconf = iface->interfaces->config_read_cb(iface->config_fname);
if (newconf == NULL)
return -1;
@@ -286,8 +288,9 @@
*/
static void hostapd_cleanup(struct hostapd_data *hapd)
{
- if (hapd->iface->ctrl_iface_deinit)
- hapd->iface->ctrl_iface_deinit(hapd);
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->ctrl_iface_deinit)
+ hapd->iface->interfaces->ctrl_iface_deinit(hapd);
hostapd_free_hapd_data(hapd);
}
@@ -679,14 +682,14 @@
set_ssid = 0;
conf->ssid.ssid_len = ssid_len;
os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
- conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
}
if (!hostapd_drv_none(hapd)) {
wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
- " and ssid '%s'",
+ " and ssid \"%s\"",
hapd->conf->iface, MAC2STR(hapd->own_addr),
- hapd->conf->ssid.ssid);
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
}
if (hostapd_setup_wpa_psk(conf)) {
@@ -696,7 +699,7 @@
/* Set SSID for the kernel driver (to be used in beacon and probe
* response frames) */
- if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
+ if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
conf->ssid.ssid_len)) {
wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
return -1;
@@ -770,8 +773,9 @@
}
#endif /* CONFIG_INTERWORKING */
- if (hapd->iface->ctrl_iface_init &&
- hapd->iface->ctrl_iface_init(hapd)) {
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->ctrl_iface_init &&
+ hapd->iface->interfaces->ctrl_iface_init(hapd)) {
wpa_printf(MSG_ERROR, "Failed to setup control interface");
return -1;
}
@@ -1045,6 +1049,292 @@
}
+#ifdef HOSTAPD
+
+void hostapd_interface_deinit_free(struct hostapd_iface *iface)
+{
+ const struct wpa_driver_ops *driver;
+ void *drv_priv;
+ if (iface == NULL)
+ return;
+ driver = iface->bss[0]->driver;
+ drv_priv = iface->bss[0]->drv_priv;
+ hostapd_interface_deinit(iface);
+ if (driver && driver->hapd_deinit && drv_priv)
+ driver->hapd_deinit(drv_priv);
+ hostapd_interface_free(iface);
+}
+
+
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
+{
+ if (hapd_iface->bss[0]->drv_priv != NULL) {
+ wpa_printf(MSG_ERROR, "Interface %s already enabled",
+ hapd_iface->conf->bss[0].iface);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Enable interface %s",
+ hapd_iface->conf->bss[0].iface);
+
+ if (hapd_iface->interfaces == NULL ||
+ hapd_iface->interfaces->driver_init == NULL ||
+ hapd_iface->interfaces->driver_init(hapd_iface) ||
+ hostapd_setup_interface(hapd_iface)) {
+ hostapd_interface_deinit_free(hapd_iface);
+ return -1;
+ }
+ return 0;
+}
+
+
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
+{
+ size_t j;
+
+ wpa_printf(MSG_DEBUG, "Reload interface %s",
+ hapd_iface->conf->bss[0].iface);
+ for (j = 0; j < hapd_iface->num_bss; j++) {
+ hostapd_flush_old_stations(hapd_iface->bss[j],
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+#ifndef CONFIG_NO_RADIUS
+ /* TODO: update dynamic data based on changed configuration
+ * items (e.g., open/close sockets, etc.) */
+ radius_client_flush(hapd_iface->bss[j]->radius, 0);
+#endif /* CONFIG_NO_RADIUS */
+
+ hostapd_reload_bss(hapd_iface->bss[j]);
+ }
+ return 0;
+}
+
+
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
+{
+ size_t j;
+ struct hostapd_bss_config *bss = hapd_iface->bss[0]->conf;
+ const struct wpa_driver_ops *driver;
+ void *drv_priv;
+
+ if (hapd_iface == NULL)
+ return -1;
+ driver = hapd_iface->bss[0]->driver;
+ drv_priv = hapd_iface->bss[0]->drv_priv;
+
+ /* whatever hostapd_interface_deinit does */
+ for (j = 0; j < hapd_iface->num_bss; j++) {
+ struct hostapd_data *hapd = hapd_iface->bss[j];
+ hostapd_free_stas(hapd);
+ hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+ hostapd_clear_wep(hapd);
+ hostapd_free_hapd_data(hapd);
+ }
+
+ if (driver && driver->hapd_deinit && drv_priv) {
+ driver->hapd_deinit(drv_priv);
+ hapd_iface->bss[0]->drv_priv = NULL;
+ }
+
+ /* From hostapd_cleanup_iface: These were initialized in
+ * hostapd_setup_interface and hostapd_setup_interface_complete
+ */
+ hostapd_cleanup_iface_partial(hapd_iface);
+ bss->wpa = 0;
+ bss->wpa_key_mgmt = -1;
+ bss->wpa_pairwise = -1;
+
+ wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+ return 0;
+}
+
+
+static struct hostapd_iface *
+hostapd_iface_alloc(struct hapd_interfaces *interfaces)
+{
+ struct hostapd_iface **iface, *hapd_iface;
+
+ iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
+ sizeof(struct hostapd_iface *));
+ if (iface == NULL)
+ return NULL;
+ interfaces->iface = iface;
+ hapd_iface = interfaces->iface[interfaces->count] =
+ os_zalloc(sizeof(*hapd_iface));
+ if (hapd_iface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+ "the interface", __func__);
+ return NULL;
+ }
+ interfaces->count++;
+ hapd_iface->interfaces = interfaces;
+
+ return hapd_iface;
+}
+
+
+static struct hostapd_config *
+hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
+ const char *ctrl_iface)
+{
+ struct hostapd_bss_config *bss;
+ struct hostapd_config *conf;
+
+ /* Allocates memory for bss and conf */
+ conf = hostapd_config_defaults();
+ if (conf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+ "configuration", __func__);
+ return NULL;
+ }
+
+ conf->driver = wpa_drivers[0];
+ if (conf->driver == NULL) {
+ wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ bss = conf->last_bss = conf->bss;
+
+ os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+ bss->ctrl_interface = os_strdup(ctrl_iface);
+ if (bss->ctrl_interface == NULL) {
+ hostapd_config_free(conf);
+ return NULL;
+ }
+
+ /* Reading configuration file skipped, will be done in SET!
+ * From reading the configuration till the end has to be done in
+ * SET
+ */
+ return conf;
+}
+
+
+static struct hostapd_iface * hostapd_data_alloc(
+ struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+{
+ size_t i;
+ struct hostapd_iface *hapd_iface =
+ interfaces->iface[interfaces->count - 1];
+ struct hostapd_data *hapd;
+
+ hapd_iface->conf = conf;
+ hapd_iface->num_bss = conf->num_bss;
+
+ hapd_iface->bss = os_zalloc(conf->num_bss *
+ sizeof(struct hostapd_data *));
+ if (hapd_iface->bss == NULL)
+ return NULL;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ hapd = hapd_iface->bss[i] =
+ hostapd_alloc_bss_data(hapd_iface, conf,
+ &conf->bss[i]);
+ if (hapd == NULL)
+ return NULL;
+ hapd->msg_ctx = hapd;
+ }
+
+ hapd_iface->interfaces = interfaces;
+
+ return hapd_iface;
+}
+
+
+int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+ struct hostapd_config *conf = NULL;
+ struct hostapd_iface *hapd_iface = NULL;
+ char *ptr;
+ size_t i;
+
+ ptr = os_strchr(buf, ' ');
+ if (ptr == NULL)
+ return -1;
+ *ptr++ = '\0';
+
+ for (i = 0; i < interfaces->count; i++) {
+ if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+ buf)) {
+ wpa_printf(MSG_INFO, "Cannot add interface - it "
+ "already exists");
+ return -1;
+ }
+ }
+
+ hapd_iface = hostapd_iface_alloc(interfaces);
+ if (hapd_iface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+ "for interface", __func__);
+ goto fail;
+ }
+
+ conf = hostapd_config_alloc(interfaces, buf, ptr);
+ if (conf == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+ "for configuration", __func__);
+ goto fail;
+ }
+
+ hapd_iface = hostapd_data_alloc(interfaces, conf);
+ if (hapd_iface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+ "for hostapd", __func__);
+ goto fail;
+ }
+
+ if (hapd_iface->interfaces &&
+ hapd_iface->interfaces->ctrl_iface_init &&
+ hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
+ wpa_printf(MSG_ERROR, "%s: Failed to setup control "
+ "interface", __func__);
+ goto fail;
+ }
+ wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+ return 0;
+
+fail:
+ if (conf)
+ hostapd_config_free(conf);
+ if (hapd_iface) {
+ os_free(hapd_iface->bss[interfaces->count]);
+ os_free(hapd_iface);
+ }
+ return -1;
+}
+
+
+int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+ struct hostapd_iface *hapd_iface;
+ size_t i, k = 0;
+
+ for (i = 0; i < interfaces->count; i++) {
+ hapd_iface = interfaces->iface[i];
+ if (hapd_iface == NULL)
+ return -1;
+ if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+ wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+ hostapd_interface_deinit_free(hapd_iface);
+ k = i;
+ while (k < (interfaces->count - 1)) {
+ interfaces->iface[k] =
+ interfaces->iface[k + 1];
+ k++;
+ }
+ interfaces->count--;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+#endif /* HOSTAPD */
+
+
/**
* hostapd_new_assoc_sta - Notify that a new station associated with the AP
* @hapd: Pointer to BSS data
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index f7ed311..71f476c 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -23,8 +23,22 @@
enum wps_event;
union wps_event_data;
+struct hostapd_iface;
+
struct hapd_interfaces {
+ int (*reload_config)(struct hostapd_iface *iface);
+ struct hostapd_config * (*config_read_cb)(const char *config_fname);
+ int (*ctrl_iface_init)(struct hostapd_data *hapd);
+ void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
+ int (*for_each_interface)(struct hapd_interfaces *interfaces,
+ int (*cb)(struct hostapd_iface *iface,
+ void *ctx), void *ctx);
+ int (*driver_init)(struct hostapd_iface *iface);
+
size_t count;
+ int global_ctrl_sock;
+ char *global_iface_path;
+ char *global_iface_name;
struct hostapd_iface **iface;
};
@@ -182,8 +196,6 @@
struct hostapd_iface {
struct hapd_interfaces *interfaces;
void *owner;
- int (*reload_config)(struct hostapd_iface *iface);
- struct hostapd_config * (*config_read_cb)(const char *config_fname);
char *config_fname;
struct hostapd_config *conf;
@@ -241,13 +253,6 @@
u16 ht_op_mode;
void (*scan_cb)(struct hostapd_iface *iface);
-
- int (*ctrl_iface_init)(struct hostapd_data *hapd);
- void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
-
- int (*for_each_interface)(struct hapd_interfaces *interfaces,
- int (*cb)(struct hostapd_iface *iface,
- void *ctx), void *ctx);
};
/* hostapd.c */
@@ -265,6 +270,12 @@
void hostapd_interface_free(struct hostapd_iface *iface);
void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
int reassoc);
+void hostapd_interface_deinit_free(struct hostapd_iface *iface);
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
+int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
/* utils.c */
int hostapd_register_probereq_cb(struct hostapd_data *hapd,
diff --git a/src/ap/hs20.c b/src/ap/hs20.c
new file mode 100644
index 0000000..45d518b
--- /dev/null
+++ b/src/ap/hs20.c
@@ -0,0 +1,31 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "hs20.h"
+
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
+{
+ if (!hapd->conf->hs20)
+ return eid;
+ *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+ *eid++ = 5;
+ WPA_PUT_BE24(eid, OUI_WFA);
+ eid += 3;
+ *eid++ = HS20_INDICATION_OUI_TYPE;
+ /* Hotspot Configuration: DGAF Enabled */
+ *eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
+ return eid;
+}
diff --git a/src/ap/hs20.h b/src/ap/hs20.h
new file mode 100644
index 0000000..98698ce
--- /dev/null
+++ b/src/ap/hs20.h
@@ -0,0 +1,16 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_H
+#define HS20_H
+
+struct hostapd_data;
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* HS20_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 76c4211..97e1238 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -129,6 +129,8 @@
i = 0;
while (basic_rates[i] >= 0)
i++;
+ if (i)
+ i++; /* -1 termination */
os_free(iface->basic_rates);
iface->basic_rates = os_malloc(i * sizeof(int));
if (iface->basic_rates)
@@ -138,7 +140,7 @@
iface->num_rates = 0;
iface->current_rates =
- os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
+ os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
if (!iface->current_rates) {
wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
"table.");
@@ -470,7 +472,7 @@
affected_start, affected_end);
mode = iface->current_mode;
- params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
pos = 0;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 3996c90..211ee1b 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -311,6 +311,8 @@
int has_psk = 0;
u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
size_t resp_ies_len = 0;
+ char *identity = NULL;
+ char *radius_cui = NULL;
if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
printf("handle_auth - too short payload (len=%lu)\n",
@@ -372,7 +374,7 @@
res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
&session_timeout,
&acct_interim_interval, &vlan_id,
- psk, &has_psk);
+ psk, &has_psk, &identity, &radius_cui);
if (res == HOSTAPD_ACL_REJECT) {
printf("Station " MACSTR " not allowed to authenticate.\n",
@@ -421,6 +423,11 @@
sta->psk = NULL;
}
+ sta->identity = identity;
+ identity = NULL;
+ sta->radius_cui = radius_cui;
+ radius_cui = NULL;
+
sta->flags &= ~WLAN_STA_PREAUTH;
ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
@@ -482,6 +489,9 @@
}
fail:
+ os_free(identity);
+ os_free(radius_cui);
+
send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
auth_transaction + 1, resp, resp_ies, resp_ies_len);
}
@@ -576,35 +586,20 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (elems->supp_rates_len > sizeof(sta->supported_rates)) {
+ if (elems->supp_rates_len + elems->ext_supp_rates_len >
+ sizeof(sta->supported_rates)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "Invalid supported rates element length %d",
- elems->supp_rates_len);
+ "Invalid supported rates element length %d+%d",
+ elems->supp_rates_len,
+ elems->ext_supp_rates_len);
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- os_memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
- os_memcpy(sta->supported_rates, elems->supp_rates,
- elems->supp_rates_len);
- sta->supported_rates_len = elems->supp_rates_len;
-
- if (elems->ext_supp_rates) {
- if (elems->supp_rates_len + elems->ext_supp_rates_len >
- sizeof(sta->supported_rates)) {
- hostapd_logger(hapd, sta->addr,
- HOSTAPD_MODULE_IEEE80211,
- HOSTAPD_LEVEL_DEBUG,
- "Invalid supported rates element length"
- " %d+%d", elems->supp_rates_len,
- elems->ext_supp_rates_len);
- return WLAN_STATUS_UNSPECIFIED_FAILURE;
- }
-
- os_memcpy(sta->supported_rates + elems->supp_rates_len,
- elems->ext_supp_rates, elems->ext_supp_rates_len);
- sta->supported_rates_len += elems->ext_supp_rates_len;
- }
+ sta->supported_rates_len = merge_byte_arrays(
+ sta->supported_rates, sizeof(sta->supported_rates),
+ elems->supp_rates, elems->supp_rates_len,
+ elems->ext_supp_rates, elems->ext_supp_rates_len);
return WLAN_STATUS_SUCCESS;
}
@@ -648,6 +643,20 @@
}
#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 && hapd->iconf->require_vht &&
+ !(sta->flags & WLAN_STA_VHT)) {
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "Station does not support "
+ "mandatory VHT PHY - reject association");
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+#endif /* CONFIG_IEEE80211AC */
+
if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
wpa_ie = elems.rsn_ie;
wpa_ie_len = elems.rsn_ie_len;
@@ -771,7 +780,7 @@
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211N
- if ((sta->flags & WLAN_STA_HT) &&
+ if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@@ -875,6 +884,11 @@
p = hostapd_eid_ht_operation(hapd, p);
#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+ p = hostapd_eid_vht_capabilities(hapd, p);
+ p = hostapd_eid_vht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
p = hostapd_eid_ext_capab(hapd, p);
p = hostapd_eid_bss_max_idle_period(hapd, p);
@@ -1337,7 +1351,10 @@
os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
resp->u.action.category |= 0x80;
- hostapd_drv_send_mlme(hapd, resp, len, 0);
+ if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+ wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
+ "Action frame");
+ }
os_free(resp);
}
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 9993bee..1e5800d 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -56,6 +56,8 @@
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *ht_capab, size_t ht_capab_len);
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_capab, size_t vht_capab_len);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
const u8 *buf, size_t len, int ack);
void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index 0c4c5f3..63ae345 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -22,6 +22,7 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "ieee802_11.h"
+#include "ieee802_1x.h"
#include "ieee802_11_auth.h"
#define RADIUS_ACL_TIMEOUT 30
@@ -37,6 +38,8 @@
int vlan_id;
int has_psk;
u8 psk[PMK_LEN];
+ char *identity;
+ char *radius_cui;
};
@@ -51,6 +54,14 @@
#ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
+{
+ os_free(e->identity);
+ os_free(e->radius_cui);
+ os_free(e);
+}
+
+
static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
{
struct hostapd_cached_radius_acl *prev;
@@ -58,7 +69,7 @@
while (acl_cache) {
prev = acl_cache;
acl_cache = acl_cache->next;
- os_free(prev);
+ hostapd_acl_cache_free_entry(prev);
}
}
@@ -66,35 +77,45 @@
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk)
+ u8 *psk, int *has_psk, char **identity,
+ char **radius_cui)
{
struct hostapd_cached_radius_acl *entry;
struct os_time now;
os_get_time(&now);
- entry = hapd->acl_cache;
- while (entry) {
- if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
- if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
- return -1; /* entry has expired */
- if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
- if (session_timeout)
- *session_timeout =
- entry->session_timeout;
- if (acct_interim_interval)
- *acct_interim_interval =
- entry->acct_interim_interval;
- if (vlan_id)
- *vlan_id = entry->vlan_id;
- if (psk)
- os_memcpy(psk, entry->psk, PMK_LEN);
- if (has_psk)
- *has_psk = entry->has_psk;
- return entry->accepted;
+ for (entry = hapd->acl_cache; entry; entry = entry->next) {
+ if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
+ continue;
+
+ if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+ return -1; /* entry has expired */
+ if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+ if (session_timeout)
+ *session_timeout = entry->session_timeout;
+ if (acct_interim_interval)
+ *acct_interim_interval =
+ entry->acct_interim_interval;
+ if (vlan_id)
+ *vlan_id = entry->vlan_id;
+ if (psk)
+ os_memcpy(psk, entry->psk, PMK_LEN);
+ if (has_psk)
+ *has_psk = entry->has_psk;
+ if (identity) {
+ if (entry->identity)
+ *identity = os_strdup(entry->identity);
+ else
+ *identity = NULL;
}
-
- entry = entry->next;
+ if (radius_cui) {
+ if (entry->radius_cui)
+ *radius_cui = os_strdup(entry->radius_cui);
+ else
+ *radius_cui = NULL;
+ }
+ return entry->accepted;
}
return -1;
@@ -140,37 +161,9 @@
goto fail;
}
- if (hapd->conf->own_ip_addr.af == AF_INET &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
+ if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
+ NULL, msg) < 0)
goto fail;
- }
-
-#ifdef CONFIG_IPV6
- if (hapd->conf->own_ip_addr.af == AF_INET6 &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
- goto fail;
- }
-#endif /* CONFIG_IPV6 */
-
- if (hapd->conf->nas_identifier &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
- (u8 *) hapd->conf->nas_identifier,
- os_strlen(hapd->conf->nas_identifier))) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
- goto fail;
- }
os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
MAC2STR(addr));
@@ -180,12 +173,6 @@
goto fail;
}
- if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
- RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
- wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
- goto fail;
- }
-
os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, os_strlen(buf))) {
@@ -215,12 +202,18 @@
* @vlan_id: Buffer for returning VLAN ID
* @psk: Buffer for returning WPA PSK
* @has_psk: Buffer for indicating whether psk was filled
+ * @identity: Buffer for returning identity (from RADIUS)
+ * @radius_cui: Buffer for returning CUI (from RADIUS)
* Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ *
+ * The caller is responsible for freeing the returned *identity and *radius_cui
+ * values with os_free().
*/
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk)
+ u8 *psk, int *has_psk, char **identity,
+ char **radius_cui)
{
if (session_timeout)
*session_timeout = 0;
@@ -232,6 +225,10 @@
*has_psk = 0;
if (psk)
os_memset(psk, 0, PMK_LEN);
+ if (identity)
+ *identity = NULL;
+ if (radius_cui)
+ *radius_cui = NULL;
if (hostapd_maclist_found(hapd->conf->accept_mac,
hapd->conf->num_accept_mac, addr, vlan_id))
@@ -256,7 +253,8 @@
/* Check whether ACL cache has an entry for this station */
int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
acct_interim_interval,
- vlan_id, psk, has_psk);
+ vlan_id, psk, has_psk,
+ identity, radius_cui);
if (res == HOSTAPD_ACL_ACCEPT ||
res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
return res;
@@ -268,6 +266,14 @@
if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
/* pending query in RADIUS retransmit queue;
* do not generate a new one */
+ if (identity) {
+ os_free(*identity);
+ *identity = NULL;
+ }
+ if (radius_cui) {
+ os_free(*radius_cui);
+ *radius_cui = NULL;
+ }
return HOSTAPD_ACL_PENDING;
}
query = query->next;
@@ -333,7 +339,7 @@
hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
tmp = entry;
entry = entry->next;
- os_free(tmp);
+ hostapd_acl_cache_free_entry(tmp);
continue;
}
@@ -450,6 +456,8 @@
if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
int passphraselen;
char *passphrase;
+ u8 *buf;
+ size_t len;
if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
&cache->session_timeout) == 0)
@@ -491,6 +499,19 @@
}
os_free(passphrase);
}
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+ &buf, &len, NULL) == 0) {
+ cache->identity = os_zalloc(len + 1);
+ if (cache->identity)
+ os_memcpy(cache->identity, buf, len);
+ }
+ if (radius_msg_get_attr_ptr(
+ msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+ cache->radius_cui = os_zalloc(len + 1);
+ if (cache->radius_cui)
+ os_memcpy(cache->radius_cui, buf, len);
+ }
if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
!cache->has_psk)
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b8a4c13..0e8d1cb 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -19,7 +19,8 @@
int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
const u8 *msg, size_t len, u32 *session_timeout,
u32 *acct_interim_interval, int *vlan_id,
- u8 *psk, int *has_psk);
+ u8 *psk, int *has_psk, char **identity,
+ char **radius_cui);
int hostapd_acl_init(struct hostapd_data *hapd);
void hostapd_acl_deinit(struct hostapd_data *hapd);
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 3ad33c8..7599ef8 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -61,12 +61,48 @@
oper = (struct ieee80211_vht_operation *) pos;
os_memset(oper, 0, sizeof(*oper));
+ /*
+ * center freq = 5 GHz + (5 * index)
+ * So index 42 gives center freq 5.210 GHz
+ * which is channel 42 in 5G band
+ */
+ oper->vht_op_info_chan_center_freq_seg0_idx =
+ hapd->iconf->vht_oper_centr_freq_seg0_idx;
+
oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
/* VHT Basic MCS set comes from hw */
/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
- oper->vht_basic_mcs_set = 0xfffc;
+ oper->vht_basic_mcs_set = host_to_le16(0xfffc);
pos += sizeof(*oper);
return pos;
}
+
+
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *vht_capab, size_t vht_capab_len)
+{
+ /* 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) {
+ sta->flags &= ~WLAN_STA_VHT;
+ os_free(sta->vht_capabilities);
+ sta->vht_capabilities = NULL;
+ return WLAN_STATUS_SUCCESS;
+ }
+
+ if (sta->vht_capabilities == NULL) {
+ sta->vht_capabilities =
+ os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+ if (sta->vht_capabilities == NULL)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
+
+ sta->flags |= WLAN_STA_VHT;
+ os_memcpy(sta->vht_capabilities, vht_capab,
+ sizeof(struct ieee80211_vht_capabilities));
+
+ return WLAN_STATUS_SUCCESS;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index dd0df1d..c4d3da8 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -126,7 +126,7 @@
hdr = (struct ieee802_1x_hdr *) buf;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
key->type = EAPOL_KEY_TYPE_RC4;
- key->key_length = htons(key_len);
+ WPA_PUT_BE16(key->key_length, key_len);
wpa_get_ntp_timestamp(key->replay_counter);
if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
@@ -409,14 +409,133 @@
}
+static int add_common_radius_sta_attr(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ char buf[128];
+
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_PORT) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-Port");
+ return -1;
+ }
+
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(sta->addr));
+ buf[sizeof(buf) - 1] = '\0';
+ if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
+ return -1;
+ }
+
+ if (sta->flags & WLAN_STA_PREAUTH) {
+ os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
+ sizeof(buf));
+ } else {
+ os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+ radius_sta_rate(hapd, sta) / 2,
+ (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+ radius_mode_txt(hapd));
+ buf[sizeof(buf) - 1] = '\0';
+ }
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_CONNECT_INFO) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Connect-Info");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int add_common_radius_attr(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg)
+{
+ char buf[128];
+ struct hostapd_radius_attr *attr;
+
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_IP_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+ (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
+ return -1;
+ }
+
+#ifdef CONFIG_IPV6
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+ hapd->conf->own_ip_addr.af == AF_INET6 &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+ (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
+ return -1;
+ }
+#endif /* CONFIG_IPV6 */
+
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_IDENTIFIER) &&
+ hapd->conf->nas_identifier &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+ (u8 *) hapd->conf->nas_identifier,
+ os_strlen(hapd->conf->nas_identifier))) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
+ return -1;
+ }
+
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
+ MAC2STR(hapd->own_addr),
+ wpa_ssid_txt(hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len));
+ buf[sizeof(buf) - 1] = '\0';
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_CALLED_STATION_ID) &&
+ !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+ (u8 *) buf, os_strlen(buf))) {
+ wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
+ return -1;
+ }
+
+ if (!hostapd_config_get_radius_attr(req_attr,
+ RADIUS_ATTR_NAS_PORT_TYPE) &&
+ !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+ RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
+ wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
+ return -1;
+ }
+
+ if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
+ return -1;
+
+ for (attr = req_attr; attr; attr = attr->next) {
+ if (!radius_msg_add_attr(msg, attr->type,
+ wpabuf_head(attr->val),
+ wpabuf_len(attr->val))) {
+ wpa_printf(MSG_ERROR, "Could not add RADIUS "
+ "attribute");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta,
const u8 *eap, size_t len)
{
struct radius_msg *msg;
- char buf[128];
struct eapol_state_machine *sm = sta->eapol_sm;
- struct hostapd_radius_attr *attr;
if (sm == NULL)
return;
@@ -443,62 +562,9 @@
goto fail;
}
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_IP_ADDRESS) &&
- hapd->conf->own_ip_addr.af == AF_INET &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
- printf("Could not add NAS-IP-Address\n");
+ if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
+ msg) < 0)
goto fail;
- }
-
-#ifdef CONFIG_IPV6
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
- hapd->conf->own_ip_addr.af == AF_INET6 &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
- (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
- printf("Could not add NAS-IPv6-Address\n");
- goto fail;
- }
-#endif /* CONFIG_IPV6 */
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_IDENTIFIER) &&
- hapd->conf->nas_identifier &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
- (u8 *) hapd->conf->nas_identifier,
- os_strlen(hapd->conf->nas_identifier))) {
- printf("Could not add NAS-Identifier\n");
- goto fail;
- }
-
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_PORT) &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
- printf("Could not add NAS-Port\n");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
- buf[sizeof(buf) - 1] = '\0';
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_CALLED_STATION_ID) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Called-Station-Id\n");
- goto fail;
- }
-
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
- MAC2STR(sta->addr));
- buf[sizeof(buf) - 1] = '\0';
- if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Calling-Station-Id\n");
- goto fail;
- }
/* TODO: should probably check MTU from driver config; 2304 is max for
* IEEE 802.11, but use 1400 to avoid problems with too large packets
@@ -510,32 +576,6 @@
goto fail;
}
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_NAS_PORT_TYPE) &&
- !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
- RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
- printf("Could not add NAS-Port-Type\n");
- goto fail;
- }
-
- if (sta->flags & WLAN_STA_PREAUTH) {
- os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
- sizeof(buf));
- } else {
- os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
- radius_sta_rate(hapd, sta) / 2,
- (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
- radius_mode_txt(hapd));
- buf[sizeof(buf) - 1] = '\0';
- }
- if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
- RADIUS_ATTR_CONNECT_INFO) &&
- !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
- (u8 *) buf, os_strlen(buf))) {
- printf("Could not add Connect-Info\n");
- goto fail;
- }
-
if (eap && !radius_msg_add_eap(msg, eap, len)) {
printf("Could not add EAP-Message\n");
goto fail;
@@ -577,17 +617,6 @@
}
}
- for (attr = hapd->conf->radius_auth_req_attr; attr; attr = attr->next)
- {
- if (!radius_msg_add_attr(msg, attr->type,
- wpabuf_head(attr->val),
- wpabuf_len(attr->val))) {
- wpa_printf(MSG_ERROR, "Could not add RADIUS "
- "attribute");
- goto fail;
- }
- }
-
if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
goto fail;
@@ -693,7 +722,8 @@
flags |= EAPOL_SM_FROM_PMKSA_CACHE;
}
return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
- sta->wps_ie, sta->p2p_ie, sta);
+ sta->wps_ie, sta->p2p_ie, sta,
+ sta->identity, sta->radius_cui);
}
@@ -1037,9 +1067,8 @@
static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
struct sta_info *sta)
{
- u8 *eap;
- size_t len;
- struct eap_hdr *hdr;
+ struct wpabuf *eap;
+ const struct eap_hdr *hdr;
int eap_type = -1;
char buf[64];
struct radius_msg *msg;
@@ -1053,7 +1082,7 @@
msg = sm->last_recv_radius;
- eap = radius_msg_get_eap(msg, &len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
/* RFC 3579, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
@@ -1065,19 +1094,19 @@
return;
}
- if (len < sizeof(*hdr)) {
+ if (wpabuf_len(eap) < sizeof(*hdr)) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_WARNING, "too short EAP packet "
"received from authentication server");
- os_free(eap);
+ wpabuf_free(eap);
sm->eap_if->aaaEapNoReq = TRUE;
return;
}
- if (len > sizeof(*hdr))
- eap_type = eap[sizeof(*hdr)];
+ if (wpabuf_len(eap) > sizeof(*hdr))
+ eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
- hdr = (struct eap_hdr *) eap;
+ hdr = wpabuf_head(eap);
switch (hdr->code) {
case EAP_CODE_REQUEST:
if (eap_type >= 0)
@@ -1112,7 +1141,7 @@
sm->eap_if->aaaEapReq = TRUE;
wpabuf_free(sm->eap_if->aaaEapReqData);
- sm->eap_if->aaaEapReqData = wpabuf_alloc_ext_data(eap, len);
+ sm->eap_if->aaaEapReqData = eap;
}
@@ -1177,7 +1206,7 @@
if (count <= 0)
return;
- nclass = os_zalloc(count * sizeof(struct radius_attr_data));
+ nclass = os_calloc(count, sizeof(struct radius_attr_data));
if (nclass == NULL)
return;
@@ -2193,7 +2222,12 @@
* driver reorder operations.
*/
os_sleep(0, 10000);
+#ifndef ANDROID_P2P
+ /* We need not do this for driver. For AP-SME flags if we send this disassoc,
+ * the p2p_client is gettig disassoc after it has completed the assoc
+ */
ap_sta_disconnect(hapd, sta, sta->addr,
WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+#endif
}
}
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index f9b05ca..e1df940 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -1,6 +1,6 @@
/*
* hostapd / IEEE 802.1X-2004 Authenticator
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -14,38 +14,8 @@
struct eapol_state_machine;
struct hostapd_config;
struct hostapd_bss_config;
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-/* RFC 3580, 4. RC4 EAPOL-Key Frame */
-
-struct ieee802_1x_eapol_key {
- u8 type;
- u16 key_length;
- u8 replay_counter[8]; /* does not repeat within the life of the keying
- * material used to encrypt the Key field;
- * 64-bit NTP timestamp MAY be used here */
- u8 key_iv[16]; /* cryptographically random number */
- u8 key_index; /* key flag in the most significant bit:
- * 0 = broadcast (default key),
- * 1 = unicast (key mapping key); key index is in the
- * 7 least significant bits */
- u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
- * MS-MPPE-Send-Key as the key */
-
- /* followed by key: if packet body length = 44 + key length, then the
- * key field (of key_length bytes) contains the key in encrypted form;
- * if packet body length = 44, key field is absent and key_length
- * represents the number of least significant octets from
- * MS-MPPE-Send-Key attribute to be used as the keying material;
- * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
+struct hostapd_radius_attr;
+struct radius_msg;
void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
@@ -83,4 +53,9 @@
const char *radius_mode_txt(struct hostapd_data *hapd);
int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+int add_common_radius_attr(struct hostapd_data *hapd,
+ struct hostapd_radius_attr *req_attr,
+ struct sta_info *sta,
+ struct radius_msg *msg);
+
#endif /* IEEE802_1X_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 95b701c..d61177f 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -235,6 +235,8 @@
os_free(sta->ht_capabilities);
os_free(sta->psk);
+ os_free(sta->identity);
+ os_free(sta->radius_cui);
os_free(sta);
}
@@ -795,8 +797,9 @@
ap_check_sa_query_timeout(hapd, sta))
return;
- nbuf = os_realloc(sta->sa_query_trans_id,
- (sta->sa_query_count + 1) * WLAN_SA_QUERY_TR_ID_LEN);
+ nbuf = os_realloc_array(sta->sa_query_trans_id,
+ sta->sa_query_count + 1,
+ WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (sta->sa_query_count == 0) {
@@ -818,9 +821,7 @@
HOSTAPD_LEVEL_DEBUG,
"association SA Query attempt %d", sta->sa_query_count);
-#ifdef NEED_AP_MLME
ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
-#endif /* NEED_AP_MLME */
}
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index cef428d..b3c57b4 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -28,6 +28,7 @@
#define WLAN_STA_ASSOC_REQ_OK BIT(15)
#define WLAN_STA_WPS2 BIT(16)
#define WLAN_STA_GAS BIT(17)
+#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -96,7 +97,11 @@
int vlan_id;
u8 *psk; /* PSK from RADIUS authentication server */
+ char *identity; /* User-Name from RADIUS */
+ char *radius_cui; /* Chargeable-User-Identity from RADIUS */
+
struct ieee80211_ht_capabilities *ht_capabilities;
+ struct ieee80211_vht_capabilities *vht_capabilities;
#ifdef CONFIG_IEEE80211W
int sa_query_count; /* number of pending SA Query requests;
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 3e9fc08..931968c 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -23,8 +23,8 @@
{
struct hostapd_probereq_cb *n;
- n = os_realloc(hapd->probereq_cb, (hapd->num_probereq_cb + 1) *
- sizeof(struct hostapd_probereq_cb));
+ n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1,
+ sizeof(struct hostapd_probereq_cb));
if (n == NULL)
return -1;
@@ -78,7 +78,8 @@
struct prune_data data;
data.hapd = hapd;
data.addr = addr;
- if (hapd->iface->for_each_interface)
- hapd->iface->for_each_interface(hapd->iface->interfaces,
- prune_associations, &data);
+ if (hapd->iface->interfaces &&
+ hapd->iface->interfaces->for_each_interface)
+ hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, prune_associations, &data);
}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index f2f766f..7b1a9e6 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -21,6 +21,7 @@
#include "ap_config.h"
#include "ap_drv_ops.h"
#include "vlan_init.h"
+#include "vlan_util.h"
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -335,7 +336,9 @@
}
-static int vlan_rem(const char *if_name)
+#ifndef CONFIG_VLAN_NETLINK
+
+int vlan_rem(const char *if_name)
{
int fd;
struct vlan_ioctl_args if_request;
@@ -378,7 +381,7 @@
returns 1 if the interface already exists
returns 0 otherwise
*/
-static int vlan_add(const char *if_name, int vid)
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
{
int fd;
struct vlan_ioctl_args if_request;
@@ -474,6 +477,8 @@
return 0;
}
+#endif /* CONFIG_VLAN_NETLINK */
+
static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
{
@@ -481,6 +486,7 @@
char br_name[IFNAMSIZ];
struct hostapd_vlan *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
@@ -496,13 +502,22 @@
ifconfig_up(br_name);
if (tagged_interface) {
+ if (vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "%s.%d", tagged_interface,
+ vlan->vlan_id);
+ else
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "vlan%d", vlan->vlan_id);
- if (!vlan_add(tagged_interface, vlan->vlan_id))
+ ifconfig_up(tagged_interface);
+ if (!vlan_add(tagged_interface, vlan->vlan_id,
+ vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN;
- os_snprintf(vlan_ifname, sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
-
if (!br_addif(br_name, vlan_ifname))
vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
@@ -527,6 +542,7 @@
char br_name[IFNAMSIZ];
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;
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
@@ -541,8 +557,16 @@
br_delif(br_name, vlan->ifname);
if (tagged_interface) {
- os_snprintf(vlan_ifname, sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
+ if (vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname,
+ sizeof(vlan_ifname),
+ "%s.%d", tagged_interface,
+ vlan->vlan_id);
+ else
+ 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);
@@ -682,7 +706,12 @@
if (priv == NULL)
return NULL;
- vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+#ifndef CONFIG_VLAN_NETLINK
+ vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+#endif /* CONFIG_VLAN_NETLINK */
priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (priv->s < 0) {
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
new file mode 100644
index 0000000..cc54051
--- /dev/null
+++ b/src/ap/vlan_util.c
@@ -0,0 +1,177 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "vlan_util.h"
+
+/*
+ * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
+ * tagged interface 'if_name'.
+ *
+ * returns -1 on error
+ * returns 1 if the interface already exists
+ * returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+ int ret = -1;
+ struct nl_sock *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *rlink = NULL;
+ int if_idx = 0;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
+ "vlan_if_name=%s)", if_name, vid, vlan_if_name);
+
+ if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ vlan_if_name);
+ return -1;
+ }
+
+ handle = nl_socket_alloc();
+ if (!handle) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+ goto vlan_add_error;
+ }
+
+ if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+ goto vlan_add_error;
+ }
+
+ if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+ cache = NULL;
+ wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+ goto vlan_add_error;
+ }
+
+ if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
+ /* link does not exist */
+ wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
+ if_name);
+ goto vlan_add_error;
+ }
+
+ if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
+ /* link does exist */
+ rtnl_link_put(rlink);
+ rlink = NULL;
+ wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
+ vlan_if_name);
+ ret = 1;
+ goto vlan_add_error;
+ }
+
+ rlink = rtnl_link_alloc();
+ if (!rlink) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
+ goto vlan_add_error;
+ }
+
+ if (rtnl_link_set_type(rlink, "vlan") < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
+ 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");
+ goto vlan_add_error;
+ }
+
+ if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 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);
+ goto vlan_add_error;
+ }
+
+ ret = 0;
+
+vlan_add_error:
+ if (rlink)
+ rtnl_link_put(rlink);
+ if (cache)
+ nl_cache_free(cache);
+ if (handle)
+ nl_socket_free(handle);
+ return ret;
+}
+
+
+int vlan_rem(const char *if_name)
+{
+ int ret = -1;
+ struct nl_sock *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *rlink = NULL;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
+
+ handle = nl_socket_alloc();
+ if (!handle) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+ goto vlan_rem_error;
+ }
+
+ if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+ goto vlan_rem_error;
+ }
+
+ if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+ cache = NULL;
+ wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+ goto vlan_rem_error;
+ }
+
+ if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
+ /* link does not exist */
+ wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
+ 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);
+ goto vlan_rem_error;
+ }
+
+ ret = 0;
+
+vlan_rem_error:
+ if (rlink)
+ rtnl_link_put(rlink);
+ if (cache)
+ nl_cache_free(cache);
+ if (handle)
+ nl_socket_free(handle);
+ return ret;
+}
diff --git a/src/ap/vlan_util.h b/src/ap/vlan_util.h
new file mode 100644
index 0000000..bef5a16
--- /dev/null
+++ b/src/ap/vlan_util.h
@@ -0,0 +1,15 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_UTIL_H
+#define VLAN_UTIL_H
+
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
+int vlan_rem(const char *if_name);
+
+#endif /* VLAN_UTIL_H */
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
new file mode 100644
index 0000000..2594404
--- /dev/null
+++ b/src/ap/wnm_ap.c
@@ -0,0 +1,258 @@
+/*
+ * hostapd - WNM
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
+#include "wnm_ap.h"
+
+#define MAX_TFS_IE_LEN 1024
+
+#ifdef CONFIG_IEEE80211V
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+ u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+ return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+ u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+ return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.response */
+static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
+ const u8 *addr, u8 dialog_token,
+ u8 action_type, u16 intval)
+{
+ struct ieee80211_mgmt *mgmt;
+ int res;
+ size_t len;
+ size_t gtk_elem_len = 0;
+ size_t igtk_elem_len = 0;
+ struct wnm_sleep_element wnmsleep_ie;
+ u8 *wnmtfs_ie;
+ u8 wnmsleep_ie_len;
+ u16 wnmtfs_ie_len;
+ u8 *pos;
+ struct sta_info *sta;
+ enum wnm_oper tfs_oper = action_type == 0 ? WNM_SLEEP_TFS_RESP_IE_ADD :
+ WNM_SLEEP_TFS_RESP_IE_NONE;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+ return -EINVAL;
+ }
+
+ /* WNM-Sleep Mode IE */
+ os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element));
+ wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+ wnmsleep_ie.eid = WLAN_EID_WNMSLEEP;
+ wnmsleep_ie.len = wnmsleep_ie_len - 2;
+ wnmsleep_ie.action_type = action_type;
+ wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
+ wnmsleep_ie.intval = intval;
+
+ /* TFS IE(s) */
+ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+ if (wnmtfs_ie == NULL)
+ return -1;
+ if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len,
+ tfs_oper)) {
+ wnmtfs_ie_len = 0;
+ os_free(wnmtfs_ie);
+ wnmtfs_ie = NULL;
+ }
+
+#define MAX_GTK_SUBELEM_LEN 45
+#define MAX_IGTK_SUBELEM_LEN 26
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
+ MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+ if (mgmt == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+ "WNM-Sleep Response action frame");
+ return -1;
+ }
+ os_memcpy(mgmt->da, addr, ETH_ALEN);
+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP;
+ mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
+ pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
+ /* add key data if MFP is enabled */
+ if (wpa_auth_uses_mfp(sta->wpa_sm) || action_type != 1){
+ mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
+ } else {
+ gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
+ pos += gtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
+ (int) gtk_elem_len);
+#ifdef CONFIG_IEEE80211W
+ res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
+ if (res < 0) {
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+ return -1;
+ }
+ igtk_elem_len = res;
+ pos += igtk_elem_len;
+ wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
+ (int) igtk_elem_len);
+#endif /* CONFIG_IEEE80211W */
+
+ WPA_PUT_LE16((u8 *)
+ &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
+ gtk_elem_len + igtk_elem_len);
+ }
+ os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
+ /* copy TFS IE here */
+ pos += wnmsleep_ie_len;
+ os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+
+ len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
+ igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+
+ /* In driver, response frame should be forced to sent when STA is in
+ * PS mode */
+ res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+ mgmt->da, &mgmt->u.action.category, len);
+
+ if (!res) {
+ wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response "
+ "frame");
+
+ /* when entering wnmsleep
+ * 1. pause the node in driver
+ * 2. mark the node so that AP won't update GTK/IGTK during
+ * WNM Sleep
+ */
+ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
+ wnmsleep_ie.action_type == 0) {
+ hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
+ addr, NULL, NULL);
+ wpa_set_wnmsleep(sta->wpa_sm, 1);
+ }
+ /* when exiting wnmsleep
+ * 1. unmark the node
+ * 2. start GTK/IGTK update if MFP is not used
+ * 3. unpause the node in driver
+ */
+ if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
+ wnmsleep_ie.action_type == 1) {
+ wpa_set_wnmsleep(sta->wpa_sm, 0);
+ hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
+ addr, NULL, NULL);
+ if (wpa_auth_uses_mfp(sta->wpa_sm) && action_type == 1)
+ wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
+ }
+ } else
+ wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame");
+
+#undef MAX_GTK_SUBELEM_LEN
+#undef MAX_IGTK_SUBELEM_LEN
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+ return res;
+}
+
+
+static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
+ const u8 *addr, const u8 *frm, int len)
+{
+ /*
+ * Action [1] | Dialog Token [1] | WNM-Sleep Mode IE |
+ * TFS Response IE
+ */
+ u8 *pos = (u8 *) frm; /* point to action field */
+ u8 dialog_token = pos[1];
+ struct wnm_sleep_element *wnmsleep_ie = NULL;
+ /* multiple TFS Req IE (assuming consecutive) */
+ u8 *tfsreq_ie_start = NULL;
+ u8 *tfsreq_ie_end = NULL;
+ u16 tfsreq_ie_len = 0;
+
+ pos += 1 + 1;
+ while (pos - frm < len - 1) {
+ u8 ie_len = *(pos+1);
+ if (*pos == WLAN_EID_WNMSLEEP)
+ wnmsleep_ie = (struct wnm_sleep_element *)pos;
+ else if (*pos == WLAN_EID_TFS_REQ) {
+ if (!tfsreq_ie_start)
+ tfsreq_ie_start = pos;
+ tfsreq_ie_end = pos;
+ } else
+ wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+ pos += ie_len + 2;
+ }
+
+ if (!wnmsleep_ie) {
+ wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+ return;
+ }
+
+ if (wnmsleep_ie->action_type == 0 && tfsreq_ie_start &&
+ tfsreq_ie_end && tfsreq_ie_end - tfsreq_ie_start >= 0) {
+ tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
+ tfsreq_ie_start;
+ wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
+ /* pass the TFS Req IE(s) to driver for processing */
+ if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+ &tfsreq_ie_len,
+ WNM_SLEEP_TFS_REQ_IE_SET))
+ wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE");
+ }
+
+ ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
+ wnmsleep_ie->action_type,
+ wnmsleep_ie->intval);
+
+ if (wnmsleep_ie->action_type == 1) {
+ /* clear the tfs after sending the resp frame */
+ ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+ &tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
+ }
+}
+
+
+void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action)
+{
+ u8 *pos = (u8 *) action->data + 1; /* point to the action field */
+ u8 act = *pos;
+
+ switch (act) {
+ case WNM_SLEEP_MODE_REQ:
+ ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
+ action->len);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif /* CONFIG_IEEE80211V */
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
new file mode 100644
index 0000000..ab7c4f1
--- /dev/null
+++ b/src/ap/wnm_ap.h
@@ -0,0 +1,17 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_AP_H
+#define WNM_AP_H
+
+struct rx_action;
+
+void ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+ struct rx_action *action);
+
+#endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 1d942a4..49d8175 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -278,25 +278,6 @@
}
-static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- group->GTK_len = 16;
- break;
- case WPA_CIPHER_TKIP:
- group->GTK_len = 32;
- break;
- case WPA_CIPHER_WEP104:
- group->GTK_len = 13;
- break;
- case WPA_CIPHER_WEP40:
- group->GTK_len = 5;
- break;
- }
-}
-
-
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
@@ -338,8 +319,7 @@
group->GTKAuthenticator = TRUE;
group->vlan_id = vlan_id;
-
- wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
@@ -514,7 +494,7 @@
* configuration.
*/
group = wpa_auth->group;
- wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
group->GInit = TRUE;
wpa_group_sm_step(wpa_auth, group);
group->GInit = FALSE;
@@ -849,7 +829,8 @@
if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
msg == GROUP_2) {
u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
- if (sm->pairwise == WPA_CIPHER_CCMP) {
+ if (sm->pairwise == WPA_CIPHER_CCMP ||
+ sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
@@ -865,7 +846,7 @@
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
"did not use HMAC-SHA1-AES "
- "with CCMP");
+ "with CCMP/GCMP");
return;
}
}
@@ -1240,7 +1221,7 @@
version = force_version;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
- else if (sm->pairwise == WPA_CIPHER_CCMP)
+ else if (sm->pairwise != WPA_CIPHER_TKIP)
version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1287,20 +1268,7 @@
WPA_PUT_BE16(key->key_info, key_info);
alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
- switch (alg) {
- case WPA_CIPHER_CCMP:
- WPA_PUT_BE16(key->key_length, 16);
- break;
- case WPA_CIPHER_TKIP:
- WPA_PUT_BE16(key->key_length, 32);
- break;
- case WPA_CIPHER_WEP40:
- WPA_PUT_BE16(key->key_length, 5);
- break;
- case WPA_CIPHER_WEP104:
- WPA_PUT_BE16(key->key_length, 13);
- break;
- }
+ WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
WPA_PUT_BE16(key->key_length, 0);
@@ -1533,22 +1501,6 @@
}
-static enum wpa_alg wpa_alg_enum(int alg)
-{
- switch (alg) {
- case WPA_CIPHER_CCMP:
- return WPA_ALG_CCMP;
- case WPA_CIPHER_TKIP:
- return WPA_ALG_TKIP;
- case WPA_CIPHER_WEP104:
- case WPA_CIPHER_WEP40:
- return WPA_ALG_WEP;
- default:
- return WPA_ALG_NONE;
- }
-}
-
-
SM_STATE(WPA_PTK, INITIALIZE)
{
SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
@@ -1773,7 +1725,7 @@
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
+ size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
@@ -1898,6 +1850,14 @@
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
os_memset(igtk.pn, 0, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random IGTK to each STA to prevent use of
+ * IGTK in the BSS.
+ */
+ if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+ return pos;
+ }
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
(const u8 *) &igtk, sizeof(igtk), NULL, 0);
@@ -1922,7 +1882,7 @@
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
@@ -1960,6 +1920,15 @@
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+ return;
+ gtk = dummy_gtk;
+ }
keyidx = gsm->GN;
_rsc = rsc;
encr = 1;
@@ -2071,15 +2040,8 @@
SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
if (sm->Pair) {
- enum wpa_alg alg;
- int klen;
- if (sm->pairwise == WPA_CIPHER_TKIP) {
- alg = WPA_ALG_TKIP;
- klen = 32;
- } else {
- alg = WPA_ALG_CCMP;
- klen = 16;
- }
+ enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
+ int klen = wpa_cipher_key_len(sm->pairwise);
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
sm->PTK.tk1, klen)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
@@ -2256,6 +2218,7 @@
struct wpa_group *gsm = sm->group;
u8 *kde, *pos, hdr[2];
size_t kde_len;
+ u8 *gtk, dummy_gtk[32];
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
@@ -2276,6 +2239,16 @@
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 1/2 msg of Group Key Handshake");
+ gtk = gsm->GTK[gsm->GN - 1];
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+ return;
+ gtk = dummy_gtk;
+ }
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm);
@@ -2287,10 +2260,10 @@
hdr[0] = gsm->GN & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
- gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
} else {
- kde = gsm->GTK[gsm->GN - 1];
+ kde = gtk;
pos = kde + gsm->GTK_len;
}
@@ -2416,6 +2389,9 @@
static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
{
+ if (ctx != NULL && ctx != sm->group)
+ return 0;
+
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
@@ -2433,6 +2409,12 @@
"marking station for GTK rekeying");
}
+#ifdef CONFIG_IEEE80211V
+ /* Do not rekey GTK/IGTK when STA is in wnmsleep */
+ if (sm->is_wnmsleep)
+ return 0;
+#endif /* CONFIG_IEEE80211V */
+
sm->group->GKeyDoneStations++;
sm->GUpdateStationKeys = TRUE;
@@ -2441,6 +2423,132 @@
}
+#ifdef CONFIG_IEEE80211V
+/* update GTK when exiting wnmsleep mode */
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
+{
+ if (sm->is_wnmsleep)
+ return;
+
+ wpa_group_update_sta(sm, NULL);
+}
+
+
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
+{
+ sm->is_wnmsleep = !!flag;
+}
+
+
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ u8 *subelem;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len, pad_len;
+ const u8 *key;
+ size_t key_len;
+ u8 keybuf[32];
+
+ /* GTK subslement */
+ key_len = gsm->GTK_len;
+ if (key_len > sizeof(keybuf))
+ return 0;
+
+ /*
+ * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
+ * than 16 bytes.
+ */
+ pad_len = key_len % 8;
+ if (pad_len)
+ pad_len = 8 - pad_len;
+ if (key_len + pad_len < 16)
+ pad_len += 8;
+ if (pad_len) {
+ os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+ os_memset(keybuf + key_len, 0, pad_len);
+ keybuf[key_len] = 0xdd;
+ key_len += pad_len;
+ key = keybuf;
+ } else
+ key = gsm->GTK[gsm->GN - 1];
+
+ /*
+ * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+ * Key[5..32] | 8 padding.
+ */
+ subelem_len = 13 + key_len + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return 0;
+
+ subelem[0] = WNM_SLEEP_SUBELEM_GTK;
+ subelem[1] = 11 + key_len + 8;
+ /* Key ID in B0-B1 of Key Info */
+ WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
+ subelem[4] = gsm->GTK_len;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5) != 0)
+ {
+ os_free(subelem);
+ return 0;
+ }
+ if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
+ os_free(subelem);
+ return 0;
+ }
+
+ os_memcpy(pos, subelem, subelem_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext GTK",
+ gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ os_free(subelem);
+
+ return subelem_len;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ u8 *subelem, *ptr;
+ struct wpa_group *gsm = sm->group;
+ size_t subelem_len;
+
+ /* IGTK subelement
+ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] |
+ * Key[16] | 8 padding */
+ subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8;
+ subelem = os_zalloc(subelem_len);
+ if (subelem == NULL)
+ return 0;
+
+ ptr = subelem;
+ *ptr++ = WNM_SLEEP_SUBELEM_IGTK;
+ *ptr++ = subelem_len - 2;
+ WPA_PUT_LE16(ptr, gsm->GN_igtk);
+ ptr += 2;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, ptr) != 0) {
+ os_free(subelem);
+ return 0;
+ }
+ ptr += 6;
+ if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+ gsm->IGTK[gsm->GN_igtk - 4], ptr)) {
+ os_free(subelem);
+ return -1;
+ }
+
+ os_memcpy(pos, subelem, subelem_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "Plaintext IGTK",
+ gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+ os_free(subelem);
+
+ return subelem_len;
+}
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211V */
+
+
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
@@ -2470,7 +2578,7 @@
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
- wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
+ wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
group->GKeyDoneStations);
}
@@ -2482,7 +2590,7 @@
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_alg_enum(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
broadcast_ether_addr, group->GN,
group->GTK[group->GN - 1], group->GTK_len) < 0)
ret = -1;
@@ -2622,23 +2730,6 @@
}
-static int wpa_cipher_bits(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return 128;
- case WPA_CIPHER_TKIP:
- return 256;
- case WPA_CIPHER_WEP104:
- return 104;
- case WPA_CIPHER_WEP40:
- return 40;
- default:
- return 0;
- }
-}
-
-
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
@@ -2701,7 +2792,7 @@
!!wpa_auth->conf.wpa_strict_rekey,
dot11RSNAConfigGroupUpdateCount,
dot11RSNAConfigPairwiseUpdateCount,
- wpa_cipher_bits(wpa_auth->conf.wpa_group),
+ wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
@@ -2744,29 +2835,10 @@
/* dot11RSNAStatsEntry */
- if (sm->wpa == WPA_VERSION_WPA) {
- if (sm->pairwise == WPA_CIPHER_CCMP)
- pairwise = WPA_CIPHER_SUITE_CCMP;
- else if (sm->pairwise == WPA_CIPHER_TKIP)
- pairwise = WPA_CIPHER_SUITE_TKIP;
- else if (sm->pairwise == WPA_CIPHER_WEP104)
- pairwise = WPA_CIPHER_SUITE_WEP104;
- else if (sm->pairwise == WPA_CIPHER_WEP40)
- pairwise = WPA_CIPHER_SUITE_WEP40;
- else if (sm->pairwise == WPA_CIPHER_NONE)
- pairwise = WPA_CIPHER_SUITE_NONE;
- } else if (sm->wpa == WPA_VERSION_WPA2) {
- if (sm->pairwise == WPA_CIPHER_CCMP)
- pairwise = RSN_CIPHER_SUITE_CCMP;
- else if (sm->pairwise == WPA_CIPHER_TKIP)
- pairwise = RSN_CIPHER_SUITE_TKIP;
- else if (sm->pairwise == WPA_CIPHER_WEP104)
- pairwise = RSN_CIPHER_SUITE_WEP104;
- else if (sm->pairwise == WPA_CIPHER_WEP40)
- pairwise = RSN_CIPHER_SUITE_WEP40;
- else if (sm->pairwise == WPA_CIPHER_NONE)
- pairwise = RSN_CIPHER_SUITE_NONE;
- } else
+ pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
+ WPA_PROTO_RSN : WPA_PROTO_WPA,
+ sm->pairwise);
+ if (pairwise == 0)
return 0;
ret = os_snprintf(
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index a07779f..91ba499 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -158,6 +158,8 @@
int pmk_r1_push;
int ft_over_ds;
#endif /* CONFIG_IEEE80211R */
+ int disable_gtk;
+ int ap_mlme;
};
typedef enum {
@@ -196,6 +198,8 @@
struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
int (*send_ft_action)(void *ctx, const u8 *dst,
const u8 *data, size_t data_len);
+ int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
+ size_t tspec_ielen);
#endif /* CONFIG_IEEE80211R */
};
@@ -278,4 +282,13 @@
void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211V
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_IEEE80211V */
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index d2ec088..48bf79b 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -52,6 +52,19 @@
}
+static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
+ const u8 *sta_addr,
+ u8 *tspec_ie, size_t tspec_ielen)
+{
+ if (wpa_auth->cb.add_tspec == NULL) {
+ wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
+ return -1;
+ }
+ return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
+ tspec_ielen);
+}
+
+
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
{
u8 *pos = buf;
@@ -471,7 +484,8 @@
#endif /* CONFIG_IEEE80211W */
-static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count,
+static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
+ u8 *pos, u8 *end, u8 id, u8 descr_count,
const u8 *ies, size_t ies_len)
{
struct ieee802_11_elems parse;
@@ -504,7 +518,7 @@
}
#ifdef NEED_AP_MLME
- if (parse.wmm_tspec) {
+ if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
struct wmm_tspec_element *tspec;
int res;
@@ -541,13 +555,35 @@
}
#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));
+ if (res >= 0) {
+ if (res)
+ rdie->status_code = host_to_le16(res);
+ else {
+ /* TSPEC accepted; include updated TSPEC in
+ * response */
+ rdie->descr_count = 1;
+ pos += sizeof(*tspec);
+ }
+ return pos;
+ }
+ }
+
wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
return pos;
}
-static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len)
+static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
+ const u8 *ric, size_t ric_len)
{
const u8 *rpos, *start;
const struct rsn_rdie *rdie;
@@ -569,7 +605,7 @@
break;
rpos += 2 + rpos[1];
}
- pos = wpa_ft_process_rdie(pos, end, rdie->id,
+ pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
rdie->descr_count,
start, rpos - start);
}
@@ -678,7 +714,8 @@
ric_start = pos;
if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
- pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len);
+ pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
+ parse.ric_len);
if (auth_alg == WLAN_AUTH_FT)
_ftie->mic_control[1] +=
ieee802_11_ie_count(ric_start,
@@ -717,13 +754,9 @@
int klen;
/* MLME-SETKEYS.request(PTK) */
- if (sm->pairwise == WPA_CIPHER_TKIP) {
- alg = WPA_ALG_TKIP;
- klen = 32;
- } else if (sm->pairwise == WPA_CIPHER_CCMP) {
- alg = WPA_ALG_CCMP;
- klen = 16;
- } else {
+ alg = wpa_cipher_to_alg(sm->pairwise);
+ klen = wpa_cipher_key_len(sm->pairwise);
+ if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
"PTK configuration", sm->pairwise);
return;
@@ -845,7 +878,7 @@
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- ptk_len = pairwise != WPA_CIPHER_CCMP ? 64 : 48;
+ ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name,
(u8 *) &sm->PTK, ptk_len, ptk_name);
@@ -1061,8 +1094,16 @@
if (os_memcmp(mic, ftie->mic, 16) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+ wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
+ MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
+ parse.mdie - 2, parse.mdie_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
+ parse.ftie - 2, parse.ftie_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
+ parse.rsn - 2, parse.rsn_len + 2);
return WLAN_STATUS_INVALID_FTIE;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 3e5ac1d..bdc89e4 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -70,6 +70,9 @@
wconf->pmk_r1_push = conf->pmk_r1_push;
wconf->ft_over_ds = conf->ft_over_ds;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_HS20
+ wconf->disable_gtk = conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
}
@@ -181,9 +184,15 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = ap_get_sta(hapd, addr);
- if (sta && sta->psk)
- return sta->psk;
- return hostapd_get_psk(hapd->conf, addr, prev_psk);
+ const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+ /*
+ * This is about to iterate over all psks, prev_psk gives the last
+ * returned psk which should not be returned again.
+ * logic list (all hostapd_get_psk; sta->psk)
+ */
+ if (sta && sta->psk && !psk && sta->psk != prev_psk)
+ psk = sta->psk;
+ return psk;
}
@@ -294,12 +303,13 @@
{
struct hostapd_data *hapd = ctx;
struct wpa_auth_iface_iter_data data;
- if (hapd->iface->for_each_interface == NULL)
+ if (hapd->iface->interfaces == NULL ||
+ hapd->iface->interfaces->for_each_interface == NULL)
return -1;
data.cb = cb;
data.cb_ctx = cb_ctx;
- return hapd->iface->for_each_interface(hapd->iface->interfaces,
- wpa_auth_iface_iter, &data);
+ return hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, wpa_auth_iface_iter, &data);
}
@@ -351,16 +361,17 @@
int ret;
#ifdef CONFIG_IEEE80211R
- if (proto == ETH_P_RRB && hapd->iface->for_each_interface) {
+ if (proto == ETH_P_RRB && hapd->iface->interfaces &&
+ hapd->iface->interfaces->for_each_interface) {
int res;
struct wpa_auth_ft_iface_iter_data idata;
idata.src_hapd = hapd;
idata.dst = dst;
idata.data = data;
idata.data_len = data_len;
- res = hapd->iface->for_each_interface(hapd->iface->interfaces,
- hostapd_wpa_auth_ft_iter,
- &idata);
+ res = hapd->iface->interfaces->for_each_interface(
+ hapd->iface->interfaces, hostapd_wpa_auth_ft_iter,
+ &idata);
if (res == 1)
return data_len;
}
@@ -425,6 +436,9 @@
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+ return NULL;
+
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
@@ -458,6 +472,14 @@
len - sizeof(*ethhdr));
}
+
+static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
+ u8 *tspec_ie, size_t tspec_ielen)
+{
+ struct hostapd_data *hapd = ctx;
+ return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
+}
+
#endif /* CONFIG_IEEE80211R */
@@ -471,6 +493,8 @@
hostapd_wpa_auth_conf(hapd->conf, &_conf);
if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
_conf.tx_status = 1;
+ if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
+ _conf.ap_mlme = 1;
os_memset(&cb, 0, sizeof(cb));
cb.ctx = hapd;
cb.logger = hostapd_wpa_auth_logger;
@@ -489,6 +513,7 @@
#ifdef CONFIG_IEEE80211R
cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
cb.add_sta = hostapd_wpa_auth_add_sta;
+ cb.add_tspec = hostapd_wpa_auth_add_tspec;
#endif /* CONFIG_IEEE80211R */
hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
if (hapd->wpa_auth == NULL) {
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index b223576..d5cf2c5 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -87,6 +87,9 @@
unsigned int ft_completed:1;
unsigned int pmk_r1_name_valid:1;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211V
+ unsigned int is_wnmsleep:1;
+#endif /* CONFIG_IEEE80211V */
u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
int req_replay_counter_used;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index f687182..1786230 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -29,6 +29,7 @@
struct wpa_ie_hdr *hdr;
int num_suites;
u8 *pos, *count;
+ u32 suite;
hdr = (struct wpa_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
@@ -36,46 +37,25 @@
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
- if (conf->wpa_group == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
- } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
+ if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
- num_suites = 0;
count = pos;
pos += 2;
- if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- pos += WPA_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- pos += WPA_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
- pos += WPA_SELECTOR_LEN;
- num_suites++;
- }
-
+ num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
if (num_suites == 0) {
wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
conf->wpa_pairwise);
return -1;
}
+ pos += num_suites * WPA_SELECTOR_LEN;
WPA_PUT_LE16(count, num_suites);
num_suites = 0;
@@ -112,28 +92,23 @@
const u8 *pmkid)
{
struct rsn_ie_hdr *hdr;
- int num_suites;
+ int num_suites, res;
u8 *pos, *count;
u16 capab;
+ u32 suite;
hdr = (struct rsn_ie_hdr *) buf;
hdr->elem_id = WLAN_EID_RSN;
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
- if (conf->wpa_group == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
- } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+ if (suite == 0) {
wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
conf->wpa_group);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
num_suites = 0;
@@ -148,21 +123,9 @@
}
#endif /* CONFIG_RSN_TESTING */
- if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
- if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
- pos += RSN_SELECTOR_LEN;
- num_suites++;
- }
+ res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+ num_suites += res;
+ pos += res * RSN_SELECTOR_LEN;
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -450,30 +413,16 @@
selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
- selector = RSN_CIPHER_SUITE_CCMP;
- if (data.pairwise_cipher & WPA_CIPHER_CCMP)
+ selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+ data.pairwise_cipher);
+ if (!selector)
selector = RSN_CIPHER_SUITE_CCMP;
- else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
- selector = RSN_CIPHER_SUITE_TKIP;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
- selector = RSN_CIPHER_SUITE_WEP104;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
- selector = RSN_CIPHER_SUITE_WEP40;
- else if (data.pairwise_cipher & WPA_CIPHER_NONE)
- selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
- selector = RSN_CIPHER_SUITE_CCMP;
- if (data.group_cipher & WPA_CIPHER_CCMP)
+ selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+ data.group_cipher);
+ if (!selector)
selector = RSN_CIPHER_SUITE_CCMP;
- else if (data.group_cipher & WPA_CIPHER_TKIP)
- selector = RSN_CIPHER_SUITE_TKIP;
- else if (data.group_cipher & WPA_CIPHER_WEP104)
- selector = RSN_CIPHER_SUITE_WEP104;
- else if (data.group_cipher & WPA_CIPHER_WEP40)
- selector = RSN_CIPHER_SUITE_WEP40;
- else if (data.group_cipher & WPA_CIPHER_NONE)
- selector = RSN_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
} else {
res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
@@ -485,30 +434,16 @@
selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
- selector = WPA_CIPHER_SUITE_TKIP;
- if (data.pairwise_cipher & WPA_CIPHER_CCMP)
- selector = WPA_CIPHER_SUITE_CCMP;
- else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
- selector = WPA_CIPHER_SUITE_TKIP;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
- selector = WPA_CIPHER_SUITE_WEP104;
- else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
- selector = WPA_CIPHER_SUITE_WEP40;
- else if (data.pairwise_cipher & WPA_CIPHER_NONE)
- selector = WPA_CIPHER_SUITE_NONE;
+ selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+ data.pairwise_cipher);
+ if (!selector)
+ selector = RSN_CIPHER_SUITE_TKIP;
wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
- selector = WPA_CIPHER_SUITE_TKIP;
- if (data.group_cipher & WPA_CIPHER_CCMP)
- selector = WPA_CIPHER_SUITE_CCMP;
- else if (data.group_cipher & WPA_CIPHER_TKIP)
+ selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+ data.group_cipher);
+ if (!selector)
selector = WPA_CIPHER_SUITE_TKIP;
- else if (data.group_cipher & WPA_CIPHER_WEP104)
- selector = WPA_CIPHER_SUITE_WEP104;
- else if (data.group_cipher & WPA_CIPHER_WEP40)
- selector = WPA_CIPHER_SUITE_WEP40;
- else if (data.group_cipher & WPA_CIPHER_NONE)
- selector = WPA_CIPHER_SUITE_NONE;
wpa_auth->dot11RSNAGroupCipherSelected = selector;
}
if (res) {
@@ -607,6 +542,8 @@
if (ciphers & WPA_CIPHER_CCMP)
sm->pairwise = WPA_CIPHER_CCMP;
+ else if (ciphers & WPA_CIPHER_GCMP)
+ sm->pairwise = WPA_CIPHER_GCMP;
else
sm->pairwise = WPA_CIPHER_TKIP;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 07ce06c..5e44c72 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -13,7 +13,6 @@
#include "utils/uuid.h"
#include "crypto/dh_groups.h"
#include "crypto/dh_group5.h"
-#include "crypto/random.h"
#include "common/wpa_ctrl.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -77,10 +76,11 @@
struct wps_for_each_data data;
data.func = func;
data.ctx = ctx;
- if (iface->for_each_interface == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->for_each_interface == NULL)
return wps_for_each(iface, &data);
- return iface->for_each_interface(iface->interfaces, wps_for_each,
- &data);
+ return iface->interfaces->for_each_interface(iface->interfaces,
+ wps_for_each, &data);
}
@@ -257,7 +257,8 @@
struct hostapd_iface *iface = eloop_data;
wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
- if (iface->reload_config(iface) < 0) {
+ if (iface->interfaces == NULL ||
+ iface->interfaces->reload_config(iface) < 0) {
wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
"configuration");
}
@@ -344,6 +345,8 @@
}
hapd->wps->wps_state = WPS_STATE_CONFIGURED;
+ if (hapd->iface->config_fname == NULL)
+ return 0;
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
@@ -371,10 +374,17 @@
fprintf(nconf, "wps_state=2\n");
- fprintf(nconf, "ssid=");
- for (i = 0; i < cred->ssid_len; i++)
- fputc(cred->ssid[i], nconf);
- fprintf(nconf, "\n");
+ if (is_hex(cred->ssid, cred->ssid_len)) {
+ fprintf(nconf, "ssid2=");
+ for (i = 0; i < cred->ssid_len; i++)
+ fprintf(nconf, "%02x", cred->ssid[i]);
+ fprintf(nconf, "\n");
+ } else {
+ fprintf(nconf, "ssid=");
+ for (i = 0; i < cred->ssid_len; i++)
+ fputc(cred->ssid[i], nconf);
+ fprintf(nconf, "\n");
+ }
if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
(cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
@@ -464,6 +474,7 @@
multi_bss = 1;
if (!multi_bss &&
(str_starts(buf, "ssid=") ||
+ str_starts(buf, "ssid2=") ||
str_starts(buf, "auth_algs=") ||
str_starts(buf, "wep_default_key=") ||
str_starts(buf, "wep_key") ||
@@ -710,10 +721,12 @@
static const u8 * get_own_uuid(struct hostapd_iface *iface)
{
const u8 *uuid;
- if (iface->for_each_interface == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->for_each_interface == NULL)
return NULL;
uuid = NULL;
- iface->for_each_interface(iface->interfaces, get_uuid_cb, &uuid);
+ iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
+ &uuid);
return uuid;
}
@@ -729,10 +742,11 @@
static int interface_count(struct hostapd_iface *iface)
{
int count = 0;
- if (iface->for_each_interface == NULL)
+ if (iface->interfaces == NULL ||
+ iface->interfaces->for_each_interface == NULL)
return 0;
- iface->for_each_interface(iface->interfaces, count_interface_cb,
- &count);
+ iface->interfaces->for_each_interface(iface->interfaces,
+ count_interface_cb, &count);
return count;
}
diff --git a/src/common/defs.h b/src/common/defs.h
index f057ffe..db29b5d 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -26,6 +26,7 @@
#ifdef CONFIG_IEEE80211W
#define WPA_CIPHER_AES_128_CMAC BIT(5)
#endif /* CONFIG_IEEE80211W */
+#define WPA_CIPHER_GCMP BIT(6)
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
@@ -91,7 +92,8 @@
WPA_ALG_TKIP,
WPA_ALG_CCMP,
WPA_ALG_IGTK,
- WPA_ALG_PMK
+ WPA_ALG_PMK,
+ WPA_ALG_GCMP
};
/**
@@ -102,7 +104,8 @@
CIPHER_WEP40,
CIPHER_TKIP,
CIPHER_CCMP,
- CIPHER_WEP104
+ CIPHER_WEP104,
+ CIPHER_GCMP
};
/**
diff --git a/src/common/eapol_common.h b/src/common/eapol_common.h
index 4e392e7..4811f38 100644
--- a/src/common/eapol_common.h
+++ b/src/common/eapol_common.h
@@ -38,4 +38,44 @@
enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
+
+#define IEEE8021X_REPLAY_COUNTER_LEN 8
+#define IEEE8021X_KEY_SIGN_LEN 16
+#define IEEE8021X_KEY_IV_LEN 16
+
+#define IEEE8021X_KEY_INDEX_FLAG 0x80
+#define IEEE8021X_KEY_INDEX_MASK 0x03
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_eapol_key {
+ u8 type;
+ /* Note: key_length is unaligned */
+ u8 key_length[2];
+ /* does not repeat within the life of the keying material used to
+ * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
+ u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
+ u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
+ u8 key_index; /* key flag in the most significant bit:
+ * 0 = broadcast (default key),
+ * 1 = unicast (key mapping key); key index is in the
+ * 7 least significant bits */
+ /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
+ * the key */
+ u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
+
+ /* followed by key: if packet body length = 44 + key length, then the
+ * key field (of key_length bytes) contains the key in encrypted form;
+ * if packet body length = 44, key field is absent and key_length
+ * represents the number of least significant octets from
+ * MS-MPPE-Send-Key attribute to be used as the keying material;
+ * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
#endif /* EAPOL_COMMON_H */
diff --git a/src/common/gas.c b/src/common/gas.c
index a67325c..cff9254 100644
--- a/src/common/gas.c
+++ b/src/common/gas.c
@@ -1,7 +1,7 @@
/*
* Generic advertisement service (GAS) (IEEE 802.11u)
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,7 +31,7 @@
}
-static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
{
return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
size);
diff --git a/src/common/gas.h b/src/common/gas.h
index 8664a79..306adc5 100644
--- a/src/common/gas.h
+++ b/src/common/gas.h
@@ -1,7 +1,7 @@
/*
* Generic advertisement service (GAS) (IEEE 802.11u)
* Copyright (c) 2009, Atheros Communications
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#ifndef GAS_H
#define GAS_H
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
struct wpabuf * gas_build_comeback_req(u8 dialog_token);
struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
u16 comeback_delay, size_t size);
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index d65675c..d9d3cd0 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -97,6 +97,11 @@
elems->p2p = pos;
elems->p2p_len = elen;
break;
+ case WFD_OUI_TYPE:
+ /* Wi-Fi Alliance - WFD IE */
+ elems->wfd = pos;
+ elems->wfd_len = elen;
+ break;
case HS20_INDICATION_OUI_TYPE:
/* Hotspot 2.0 */
elems->hs20 = pos;
@@ -253,6 +258,14 @@
elems->ht_operation = pos;
elems->ht_operation_len = elen;
break;
+ case WLAN_EID_VHT_CAP:
+ elems->vht_capabilities = pos;
+ elems->vht_capabilities_len = elen;
+ break;
+ case WLAN_EID_VHT_OPERATION:
+ elems->vht_operation = pos;
+ elems->vht_operation_len = elen;
+ break;
case WLAN_EID_LINK_ID:
if (elen < 18)
break;
@@ -397,3 +410,75 @@
return NULL;
}
}
+
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+ const char *name, const char *val)
+{
+ int num, v;
+ const char *pos;
+ struct hostapd_wmm_ac_params *ac;
+
+ /* skip 'wme_ac_' or 'wmm_ac_' prefix */
+ pos = name + 7;
+ if (os_strncmp(pos, "be_", 3) == 0) {
+ num = 0;
+ pos += 3;
+ } else if (os_strncmp(pos, "bk_", 3) == 0) {
+ num = 1;
+ pos += 3;
+ } else if (os_strncmp(pos, "vi_", 3) == 0) {
+ num = 2;
+ pos += 3;
+ } else if (os_strncmp(pos, "vo_", 3) == 0) {
+ num = 3;
+ pos += 3;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
+ return -1;
+ }
+
+ ac = &wmm_ac_params[num];
+
+ if (os_strcmp(pos, "aifs") == 0) {
+ v = atoi(val);
+ if (v < 1 || v > 255) {
+ wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
+ return -1;
+ }
+ ac->aifs = v;
+ } else if (os_strcmp(pos, "cwmin") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ 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) {
+ wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
+ return -1;
+ }
+ ac->cwmax = v;
+ } else if (os_strcmp(pos, "txop_limit") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 0xffff) {
+ wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
+ return -1;
+ }
+ ac->txop_limit = v;
+ } else if (os_strcmp(pos, "acm") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 1) {
+ wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
+ return -1;
+ }
+ ac->admission_control_mandatory = v;
+ } else {
+ wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index d9b2b6c..bfc3eb2 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -33,8 +33,11 @@
const u8 *timeout_int;
const u8 *ht_capabilities;
const u8 *ht_operation;
+ const u8 *vht_capabilities;
+ const u8 *vht_operation;
const u8 *vendor_ht_cap;
const u8 *p2p;
+ const u8 *wfd;
const u8 *link_id;
const u8 *interworking;
const u8 *hs20;
@@ -63,8 +66,11 @@
u8 timeout_int_len;
u8 ht_capabilities_len;
u8 ht_operation_len;
+ u8 vht_capabilities_len;
+ u8 vht_operation_len;
u8 vendor_ht_cap_len;
u8 p2p_len;
+ u8 wfd_len;
u8 interworking_len;
u8 hs20_len;
u8 ext_capab_len;
@@ -81,4 +87,15 @@
struct ieee80211_hdr;
const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
+struct hostapd_wmm_ac_params {
+ int cwmin;
+ int cwmax;
+ int aifs;
+ int txop_limit; /* in units of 32us */
+ int admission_control_mandatory;
+};
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+ const char *name, const char *val);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index b4f9275..2ab7fbf 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -701,6 +701,8 @@
#define WPS_IE_VENDOR_TYPE 0x0050f204
#define OUI_WFA 0x506f9a
#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define WFD_IE_VENDOR_TYPE 0x506f9a0a
+#define WFD_OUI_TYPE 10
#define HS20_IE_VENDOR_TYPE 0x506f9a10
#define WMM_OUI_TYPE 2
@@ -923,6 +925,7 @@
P2P_SERV_BONJOUR = 1,
P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3,
+ P2P_SERV_WIFI_DISPLAY = 4,
P2P_SERV_VENDOR_SPECIFIC = 255
};
@@ -934,6 +937,20 @@
};
+enum wifi_display_subelem {
+ WFD_SUBELEM_DEVICE_INFO = 0,
+ WFD_SUBELEM_ASSOCIATED_BSSID = 1,
+ WFD_SUBELEM_AUDIO_FORMATS = 2,
+ WFD_SUBELEM_VIDEO_FORMATS = 3,
+ WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
+ WFD_SUBELEM_CONTENT_PROTECTION = 5,
+ WFD_SUBELEM_COUPLED_SINK = 6,
+ WFD_SUBELEM_EXT_CAPAB = 7,
+ WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
+ WFD_SUBELEM_SESSION_INFO = 9
+};
+
+
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@@ -946,6 +963,8 @@
#define WLAN_CIPHER_SUITE_CCMP 0x000FAC04
#define WLAN_CIPHER_SUITE_WEP104 0x000FAC05
#define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06
+#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR 0x000FAC07
+#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08
/* AKM suite selectors */
#define WLAN_AKM_SUITE_8021X 0x000FAC01
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 7a013a8..36c308a 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -43,8 +43,10 @@
u8 hash[SHA1_MAC_LEN];
switch (ver) {
+#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
return hmac_md5(key, 16, buf, len, mic);
+#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
if (hmac_sha1(key, 16, buf, len, hash))
return -1;
@@ -350,6 +352,8 @@
if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
return WPA_CIPHER_AES_128_CMAC;
#endif /* CONFIG_IEEE80211W */
+ if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
+ return WPA_CIPHER_GCMP;
return 0;
}
@@ -906,6 +910,8 @@
return "CCMP";
case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
return "CCMP+TKIP";
+ case WPA_CIPHER_GCMP:
+ return "GCMP";
default:
return "UNKNOWN";
}
@@ -1067,3 +1073,138 @@
return added;
}
#endif /* CONFIG_IEEE80211R */
+
+
+int wpa_cipher_key_len(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ case WPA_CIPHER_GCMP:
+ return 16;
+ case WPA_CIPHER_TKIP:
+ return 32;
+ case WPA_CIPHER_WEP104:
+ return 13;
+ case WPA_CIPHER_WEP40:
+ return 5;
+ }
+
+ return 0;
+}
+
+
+int wpa_cipher_rsc_len(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ case WPA_CIPHER_GCMP:
+ case WPA_CIPHER_TKIP:
+ return 6;
+ case WPA_CIPHER_WEP104:
+ case WPA_CIPHER_WEP40:
+ return 0;
+ }
+
+ return 0;
+}
+
+
+int wpa_cipher_to_alg(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_CCMP:
+ return WPA_ALG_CCMP;
+ case WPA_CIPHER_GCMP:
+ return WPA_ALG_GCMP;
+ case WPA_CIPHER_TKIP:
+ return WPA_ALG_TKIP;
+ case WPA_CIPHER_WEP104:
+ case WPA_CIPHER_WEP40:
+ return WPA_ALG_WEP;
+ }
+ return WPA_ALG_NONE;
+}
+
+
+int wpa_cipher_valid_pairwise(int cipher)
+{
+ return cipher == WPA_CIPHER_CCMP ||
+ cipher == WPA_CIPHER_GCMP ||
+ cipher == WPA_CIPHER_TKIP;
+}
+
+
+u32 wpa_cipher_to_suite(int proto, int cipher)
+{
+ if (cipher & WPA_CIPHER_CCMP)
+ return (proto == WPA_PROTO_RSN ?
+ RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+ if (cipher & WPA_CIPHER_GCMP)
+ return RSN_CIPHER_SUITE_GCMP;
+ 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);
+ return 0;
+}
+
+
+int rsn_cipher_put_suites(u8 *pos, int ciphers)
+{
+ int num_suites = 0;
+
+ if (ciphers & WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_GCMP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_NONE) {
+ RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ return num_suites;
+}
+
+
+int wpa_cipher_put_suites(u8 *pos, int ciphers)
+{
+ int num_suites = 0;
+
+ if (ciphers & WPA_CIPHER_CCMP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_TKIP) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+ if (ciphers & WPA_CIPHER_NONE) {
+ RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
+ pos += WPA_SELECTOR_LEN;
+ num_suites++;
+ }
+
+ return num_suites;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 6b50997..603166b 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -64,6 +64,7 @@
#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
#endif /* CONFIG_IEEE80211W */
#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
/* EAPOL-Key Key Data Encapsulation
* GroupKey and PeerKey require encryption, otherwise, encryption is optional.
@@ -83,6 +84,9 @@
#ifdef CONFIG_IEEE80211W
#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#endif /* CONFIG_IEEE80211W */
+#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
@@ -375,4 +379,12 @@
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_pairwise(int cipher);
+u32 wpa_cipher_to_suite(int proto, int cipher);
+int rsn_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_cipher_put_suites(u8 *pos, int ciphers);
+
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index b2b0683..58cbe6a 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -12,7 +12,12 @@
#ifdef CONFIG_CTRL_IFACE_UNIX
#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
#ifdef ANDROID
#include <dirent.h>
@@ -44,6 +49,8 @@
struct sockaddr_in local;
struct sockaddr_in dest;
char *cookie;
+ char *remote_ifname;
+ char *remote_ip;
#endif /* CONFIG_CTRL_IFACE_UDP */
#ifdef CONFIG_CTRL_IFACE_UNIX
int s;
@@ -73,6 +80,7 @@
int ret;
size_t res;
int tries = 0;
+ int flags;
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
@@ -156,6 +164,19 @@
return NULL;
}
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(ctrl->s, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
+ perror("fcntl(ctrl->s, O_NONBLOCK)");
+ /* Not fatal, continue on.*/
+ }
+ }
+
return ctrl;
}
@@ -230,6 +251,9 @@
struct wpa_ctrl *ctrl;
char buf[128];
size_t len;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ struct hostent *h;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
@@ -244,7 +268,11 @@
}
ctrl->local.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ ctrl->local.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
sizeof(ctrl->local)) < 0) {
close(ctrl->s);
@@ -255,10 +283,48 @@
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ if (ctrl_path) {
+ char *port, *name;
+ int port_id;
+
+ name = os_strdup(ctrl_path);
+ if (name == NULL) {
+ close(ctrl->s);
+ os_free(ctrl);
+ return NULL;
+ }
+ port = os_strchr(name, ':');
+
+ if (port) {
+ port_id = atoi(&port[1]);
+ port[0] = '\0';
+ } else
+ port_id = WPA_CTRL_IFACE_PORT;
+
+ h = gethostbyname(name);
+ ctrl->remote_ip = os_strdup(name);
+ os_free(name);
+ if (h == NULL) {
+ perror("gethostbyname");
+ close(ctrl->s);
+ os_free(ctrl->remote_ip);
+ os_free(ctrl);
+ return NULL;
+ }
+ ctrl->dest.sin_port = htons(port_id);
+ os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
+ h->h_length);
+ } else
+ ctrl->remote_ip = os_strdup("localhost");
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
perror("connect");
close(ctrl->s);
+ os_free(ctrl->remote_ip);
os_free(ctrl);
return NULL;
}
@@ -269,14 +335,31 @@
ctrl->cookie = os_strdup(buf);
}
+ if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
+ buf[len] = '\0';
+ ctrl->remote_ifname = os_strdup(buf);
+ }
+
return ctrl;
}
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
+{
+#define WPA_CTRL_MAX_PS_NAME 100
+ static char ps[WPA_CTRL_MAX_PS_NAME] = {};
+ os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
+ ctrl->remote_ip, ctrl->remote_ifname);
+ return ps;
+}
+
+
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
close(ctrl->s);
os_free(ctrl->cookie);
+ os_free(ctrl->remote_ifname);
+ os_free(ctrl->remote_ip);
os_free(ctrl);
}
@@ -289,6 +372,7 @@
void (*msg_cb)(char *msg, size_t len))
{
struct timeval tv;
+ struct os_time started_at;
int res;
fd_set rfds;
const char *_cmd;
@@ -315,7 +399,30 @@
_cmd_len = cmd_len;
}
+ errno = 0;
+ started_at.sec = 0;
+ started_at.usec = 0;
+retry_send:
if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+ if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
+ {
+ /*
+ * Must be a non-blocking socket... Try for a bit
+ * longer before giving up.
+ */
+ if (started_at.sec == 0)
+ os_get_time(&started_at);
+ else {
+ struct os_time n;
+ os_get_time(&n);
+ /* Try for a few seconds. */
+ if (n.sec > started_at.sec + 5)
+ goto send_err;
+ }
+ os_sleep(1, 0);
+ goto retry_send;
+ }
+ send_err:
os_free(cmd_buf);
return -1;
}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index a440b69..84f1195 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -48,6 +48,10 @@
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
/** EAP authentication failed (EAP-Failure received) */
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+/** Network block temporarily disabled (e.g., due to authentication failure) */
+#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
+/** Temporarily disabled network block re-enabled */
+#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
/** New scan results available */
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
/** wpa_supplicant state change */
@@ -133,6 +137,8 @@
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+
/* hostapd control interface - fixed message prefixes */
#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
@@ -164,6 +170,7 @@
#define WPA_BSS_MASK_WPS_SCAN BIT(13)
#define WPA_BSS_MASK_P2P_SCAN BIT(14)
#define WPA_BSS_MASK_INTERNETW BIT(15)
+#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
/* wpa_supplicant/hostapd control interface access */
@@ -290,6 +297,8 @@
*/
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
+
#ifdef ANDROID
/**
* wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
@@ -302,8 +311,11 @@
#endif /* ANDROID */
#ifdef CONFIG_CTRL_IFACE_UDP
+/* Port range for multiple wpa_supplicant instances and multiple VIFs */
#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
#endif /* CONFIG_CTRL_IFACE_UDP */
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index b221dd4..18b5054 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -31,16 +31,17 @@
md4-internal.o \
md5.o \
md5-internal.o \
- md5-non-fips.o \
milenage.o \
ms_funcs.o \
rc4.o \
sha1.o \
sha1-internal.o \
sha1-pbkdf2.o \
+ sha1-prf.o \
sha1-tlsprf.o \
sha1-tprf.o \
sha256.o \
+ sha256-prf.o \
sha256-tlsprf.o \
sha256-internal.o
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 7e61cb9..26b9acf 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -41,21 +41,6 @@
*/
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
-#ifdef CONFIG_FIPS
-/**
- * md5_vector_non_fips_allow - MD5 hash for data vector (non-FIPS use allowed)
- * @num_elem: Number of elements in the data vector
- * @addr: Pointers to the data areas
- * @len: Lengths of the data blocks
- * @mac: Buffer for the hash
- * Returns: 0 on success, -1 on failure
- */
-int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac);
-#else /* CONFIG_FIPS */
-#define md5_vector_non_fips_allow md5_vector
-#endif /* CONFIG_FIPS */
-
/**
* sha1_vector - SHA-1 hash for data vector
@@ -461,4 +446,15 @@
int rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len);
+/**
+ * crypto_get_random - Generate cryptographically strong pseudy-random bytes
+ * @buf: Buffer for data
+ * @len: Number of bytes to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * If the PRNG does not have enough entropy to ensure unpredictable byte
+ * sequence, this functions must return -1.
+ */
+int crypto_get_random(void *buf, size_t len);
+
#endif /* CRYPTO_H */
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index 8506fff..711e312 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -15,6 +15,10 @@
#include <openssl/evp.h>
#include <openssl/dh.h>
#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#ifdef CONFIG_OPENSSL_CMAC
+#include <openssl/cmac.h>
+#endif /* CONFIG_OPENSSL_CMAC */
#include "common.h"
#include "wpabuf.h"
@@ -69,21 +73,14 @@
#define NO_SHA256_WRAPPER
#endif
-static int openssl_digest_vector(const EVP_MD *type, int non_fips,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
+static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
EVP_MD_CTX ctx;
size_t i;
unsigned int mac_len;
EVP_MD_CTX_init(&ctx);
-#ifdef CONFIG_FIPS
-#ifdef OPENSSL_FIPS
- if (non_fips)
- EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
-#endif /* OPENSSL_FIPS */
-#endif /* CONFIG_FIPS */
if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -109,7 +106,7 @@
int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- return openssl_digest_vector(EVP_md4(), 0, num_elem, addr, len, mac);
+ return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
}
@@ -173,22 +170,13 @@
int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- return openssl_digest_vector(EVP_md5(), 0, num_elem, addr, len, mac);
+ return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
}
-#ifdef CONFIG_FIPS
-int md5_vector_non_fips_allow(size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
-{
- return openssl_digest_vector(EVP_md5(), 1, num_elem, addr, len, mac);
-}
-#endif /* CONFIG_FIPS */
-
-
int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
- return openssl_digest_vector(EVP_sha1(), 0, num_elem, addr, len, mac);
+ return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
}
@@ -196,60 +184,124 @@
int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
- return openssl_digest_vector(EVP_sha256(), 0, num_elem, addr, len,
- mac);
+ return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
}
#endif /* NO_SHA256_WRAPPER */
+static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
+{
+ switch (keylen) {
+ case 16:
+ return EVP_aes_128_ecb();
+ case 24:
+ return EVP_aes_192_ecb();
+ case 32:
+ return EVP_aes_256_ecb();
+ }
+
+ return NULL;
+}
+
+
void * aes_encrypt_init(const u8 *key, size_t len)
{
- AES_KEY *ak;
- ak = os_malloc(sizeof(*ak));
- if (ak == NULL)
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+
+ type = aes_get_evp_cipher(len);
+ if (type == NULL)
return NULL;
- if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
- os_free(ak);
+
+ ctx = os_malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+ EVP_CIPHER_CTX_init(ctx);
+ if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+ os_free(ctx);
return NULL;
}
- return ak;
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ return ctx;
}
void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
{
- AES_encrypt(plain, crypt, ctx);
+ EVP_CIPHER_CTX *c = ctx;
+ int clen = 16;
+ if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
}
void aes_encrypt_deinit(void *ctx)
{
- os_free(ctx);
+ EVP_CIPHER_CTX *c = ctx;
+ u8 buf[16];
+ int len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(c, buf, &len) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: "
+ "%s", ERR_error_string(ERR_get_error(), NULL));
+ }
+ if (len != 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+ "in AES encrypt", len);
+ }
+ EVP_CIPHER_CTX_cleanup(c);
+ os_free(c);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
- AES_KEY *ak;
- ak = os_malloc(sizeof(*ak));
- if (ak == NULL)
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+
+ type = aes_get_evp_cipher(len);
+ if (type == NULL)
return NULL;
- if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
- os_free(ak);
+
+ ctx = os_malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+ EVP_CIPHER_CTX_init(ctx);
+ if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+ os_free(ctx);
return NULL;
}
- return ak;
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ return ctx;
}
void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
{
- AES_decrypt(crypt, plain, ctx);
+ EVP_CIPHER_CTX *c = ctx;
+ int plen = 16;
+ if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
}
void aes_decrypt_deinit(void *ctx)
{
+ EVP_CIPHER_CTX *c = ctx;
+ u8 buf[16];
+ int len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(c, buf, &len) != 1) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: "
+ "%s", ERR_error_string(ERR_get_error(), NULL));
+ }
+ if (len != 0) {
+ wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+ "in AES decrypt", len);
+ }
+ EVP_CIPHER_CTX_cleanup(c);
os_free(ctx);
}
@@ -571,6 +623,7 @@
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
+ HMAC_CTX_init(&ctx->ctx);
#if OPENSSL_VERSION_NUMBER < 0x00909000
HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
@@ -623,3 +676,145 @@
return -1;
}
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
+ (unsigned char *) ssid,
+ ssid_len, 4096, buflen, buf) != 1)
+ return -1;
+#else /* openssl < 0.9.8 */
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+ ssid_len, 4096, buflen, buf) != 1)
+ return -1;
+#endif /* openssl < 0.9.8 */
+ return 0;
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HMAC_CTX ctx;
+ size_t i;
+ unsigned int mdlen;
+ int res;
+
+ HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
+#else /* openssl < 0.9.9 */
+ if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+ return -1;
+#endif /* openssl < 0.9.9 */
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(&ctx, addr[i], len[i]);
+
+ mdlen = 20;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Final(&ctx, mac, &mdlen);
+ res = 1;
+#else /* openssl < 0.9.9 */
+ res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+ HMAC_CTX_cleanup(&ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+ u8 *mac)
+{
+ return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HMAC_CTX ctx;
+ size_t i;
+ unsigned int mdlen;
+ int res;
+
+ HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
+#else /* openssl < 0.9.9 */
+ if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
+ return -1;
+#endif /* openssl < 0.9.9 */
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(&ctx, addr[i], len[i]);
+
+ mdlen = 32;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+ HMAC_Final(&ctx, mac, &mdlen);
+ res = 1;
+#else /* openssl < 0.9.9 */
+ res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+ HMAC_CTX_cleanup(&ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+int crypto_get_random(void *buf, size_t len)
+{
+ if (RAND_bytes(buf, len) != 1)
+ return -1;
+ return 0;
+}
+
+
+#ifdef CONFIG_OPENSSL_CMAC
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ CMAC_CTX *ctx;
+ int ret = -1;
+ size_t outlen, i;
+
+ ctx = CMAC_CTX_new();
+ if (ctx == NULL)
+ return -1;
+
+ if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ goto fail;
+ for (i = 0; i < num_elem; i++) {
+ if (!CMAC_Update(ctx, addr[i], len[i]))
+ goto fail;
+ }
+ if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16)
+ goto fail;
+
+ ret = 0;
+fail:
+ CMAC_CTX_free(ctx);
+ return ret;
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+#endif /* CONFIG_OPENSSL_CMAC */
diff --git a/src/crypto/fips_prf_openssl.c b/src/crypto/fips_prf_openssl.c
index 92f0b57..d69ecea 100644
--- a/src/crypto/fips_prf_openssl.c
+++ b/src/crypto/fips_prf_openssl.c
@@ -31,13 +31,14 @@
u8 *xpos = x;
u32 carry;
- if (seed_len > sizeof(xkey))
+ if (seed_len < sizeof(xkey))
+ os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+ else
seed_len = sizeof(xkey);
/* FIPS 186-2 + change notice 1 */
os_memcpy(xkey, seed, seed_len);
- os_memset(xkey + seed_len, 0, 64 - seed_len);
t[0] = 0x67452301;
t[1] = 0xEFCDAB89;
t[2] = 0x98BADCFE;
diff --git a/src/crypto/md5-non-fips.c b/src/crypto/md5-non-fips.c
deleted file mode 100644
index 418f782..0000000
--- a/src/crypto/md5-non-fips.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * MD5 hash implementation and interface functions (non-FIPS allowed cases)
- * Copyright (c) 2003-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 "common.h"
-#include "md5.h"
-#include "crypto.h"
-
-
-/**
- * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @num_elem: Number of elements in the data vector
- * @addr: Pointers to the data areas
- * @len: Lengths of the data blocks
- * @mac: Buffer for the hash (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac)
-{
- u8 k_pad[64]; /* padding - key XORd with ipad/opad */
- u8 tk[16];
- const u8 *_addr[6];
- size_t i, _len[6];
-
- if (num_elem > 5) {
- /*
- * Fixed limit on the number of fragments to avoid having to
- * allocate memory (which could fail).
- */
- return -1;
- }
-
- /* if key is longer than 64 bytes reset it to key = MD5(key) */
- if (key_len > 64) {
- if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
- return -1;
- key = tk;
- key_len = 16;
- }
-
- /* the HMAC_MD5 transform looks like:
- *
- * MD5(K XOR opad, MD5(K XOR ipad, text))
- *
- * where K is an n byte key
- * ipad is the byte 0x36 repeated 64 times
- * opad is the byte 0x5c repeated 64 times
- * and text is the data being protected */
-
- /* start out by storing key in ipad */
- os_memset(k_pad, 0, sizeof(k_pad));
- os_memcpy(k_pad, key, key_len);
-
- /* XOR key with ipad values */
- for (i = 0; i < 64; i++)
- k_pad[i] ^= 0x36;
-
- /* perform inner MD5 */
- _addr[0] = k_pad;
- _len[0] = 64;
- for (i = 0; i < num_elem; i++) {
- _addr[i + 1] = addr[i];
- _len[i + 1] = len[i];
- }
- if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
- return -1;
-
- os_memset(k_pad, 0, sizeof(k_pad));
- os_memcpy(k_pad, key, key_len);
- /* XOR key with opad values */
- for (i = 0; i < 64; i++)
- k_pad[i] ^= 0x5c;
-
- /* perform outer MD5 */
- _addr[0] = k_pad;
- _len[0] = 64;
- _addr[1] = mac;
- _len[1] = MD5_MAC_LEN;
- return md5_vector_non_fips_allow(2, _addr, _len, mac);
-}
-
-
-/**
- * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
- * @key: Key for HMAC operations
- * @key_len: Length of the key in bytes
- * @data: Pointers to the data area
- * @data_len: Length of the data area
- * @mac: Buffer for the hash (16 bytes)
- * Returns: 0 on success, -1 on failure
- */
-int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac)
-{
- return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
- &data_len, mac);
-}
diff --git a/src/crypto/md5.h b/src/crypto/md5.h
index 4d6e904..33f8426 100644
--- a/src/crypto/md5.h
+++ b/src/crypto/md5.h
@@ -15,15 +15,5 @@
const u8 *addr[], const size_t *len, u8 *mac);
int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac);
-#ifdef CONFIG_FIPS
-int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
- size_t num_elem, const u8 *addr[],
- const size_t *len, u8 *mac);
-int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac);
-#else /* CONFIG_FIPS */
-#define hmac_md5_vector_non_fips_allow hmac_md5_vector
-#define hmac_md5_non_fips_allow hmac_md5
-#endif /* CONFIG_FIPS */
#endif /* MD5_H */
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index 3594d84..b2bbab2 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -173,8 +173,9 @@
u8 challenge[8];
u8 password_hash[16];
- challenge_hash(peer_challenge, auth_challenge, username, username_len,
- challenge);
+ if (challenge_hash(peer_challenge, auth_challenge, username,
+ username_len, challenge))
+ return -1;
if (nt_password_hash(password, password_len, password_hash))
return -1;
challenge_response(challenge, password_hash, response);
@@ -260,8 +261,9 @@
if (sha1_vector(3, addr1, len1, response))
return -1;
- challenge_hash(peer_challenge, auth_challenge, username, username_len,
- challenge);
+ if (challenge_hash(peer_challenge, auth_challenge, username,
+ username_len, challenge))
+ return -1;
return sha1_vector(3, addr2, len2, response);
}
diff --git a/src/crypto/random.c b/src/crypto/random.c
index d85c3e6..053740e 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -29,6 +29,7 @@
#include "utils/common.h"
#include "utils/eloop.h"
+#include "crypto/crypto.h"
#include "sha1.h"
#include "random.h"
@@ -177,6 +178,27 @@
*bytes++ ^= tmp[i];
left -= siz;
}
+
+#ifdef CONFIG_FIPS
+ /* Mix in additional entropy from the crypto module */
+ left = len;
+ while (left) {
+ size_t siz, i;
+ u8 tmp[EXTRACT_LEN];
+ if (crypto_get_random(tmp, sizeof(tmp)) < 0) {
+ wpa_printf(MSG_ERROR, "random: No entropy available "
+ "for generating strong random bytes");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module",
+ tmp, sizeof(tmp));
+ siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+ for (i = 0; i < siz; i++)
+ *bytes++ ^= tmp[i];
+ left -= siz;
+ }
+#endif /* CONFIG_FIPS */
+
wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
if (entropy < len)
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 450c2a0..8effe2f 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -11,7 +11,7 @@
#include "common.h"
#include "sha1.h"
-static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
+static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid,
size_t ssid_len, int iterations, unsigned int count,
u8 *digest)
{
@@ -22,7 +22,7 @@
size_t len[2];
size_t passphrase_len = os_strlen(passphrase);
- addr[0] = (u8 *) ssid;
+ addr[0] = ssid;
len[0] = ssid_len;
addr[1] = count_buf;
len[1] = 4;
@@ -69,7 +69,7 @@
* iterations is set to 4096 and buflen to 32. This function is described in
* IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
*/
-int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
unsigned int count = 0;
diff --git a/src/crypto/sha1-prf.c b/src/crypto/sha1-prf.c
new file mode 100644
index 0000000..90b9e74
--- /dev/null
+++ b/src/crypto/sha1-prf.c
@@ -0,0 +1,66 @@
+/*
+ * SHA1-based PRF
+ * Copyright (c) 2003-2005, 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 "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
+ * @key: Key for PRF
+ * @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
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., PMK in IEEE 802.11i).
+ */
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ u8 counter = 0;
+ size_t pos, plen;
+ u8 hash[SHA1_MAC_LEN];
+ size_t label_len = os_strlen(label) + 1;
+ const unsigned char *addr[3];
+ size_t len[3];
+
+ addr[0] = (u8 *) label;
+ len[0] = label_len;
+ addr[1] = data;
+ len[1] = data_len;
+ addr[2] = &counter;
+ len[2] = 1;
+
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ if (plen >= SHA1_MAC_LEN) {
+ if (hmac_sha1_vector(key, key_len, 3, addr, len,
+ &buf[pos]))
+ return -1;
+ pos += SHA1_MAC_LEN;
+ } else {
+ if (hmac_sha1_vector(key, key_len, 3, addr, len,
+ hash))
+ return -1;
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+
+ return 0;
+}
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index e79265b..0effd9b 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -71,19 +71,16 @@
S2--;
}
- hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
- A_MD5);
+ hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
MD5_pos = MD5_MAC_LEN;
SHA1_pos = SHA1_MAC_LEN;
for (i = 0; i < outlen; i++) {
if (MD5_pos == MD5_MAC_LEN) {
- hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr,
- MD5_len, P_MD5);
+ hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
MD5_pos = 0;
- hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN,
- A_MD5);
+ hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
}
if (SHA1_pos == SHA1_MAC_LEN) {
hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index 274d81f..d48c77d 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -102,56 +102,3 @@
{
return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
}
-
-
-/**
- * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
- * @key: Key for PRF
- * @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
- * Returns: 0 on success, -1 of failure
- *
- * This function is used to derive new, cryptographically separate keys from a
- * given key (e.g., PMK in IEEE 802.11i).
- */
-int sha1_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
-{
- u8 counter = 0;
- size_t pos, plen;
- u8 hash[SHA1_MAC_LEN];
- size_t label_len = os_strlen(label) + 1;
- const unsigned char *addr[3];
- size_t len[3];
-
- addr[0] = (u8 *) label;
- len[0] = label_len;
- addr[1] = data;
- len[1] = data_len;
- addr[2] = &counter;
- len[2] = 1;
-
- pos = 0;
- while (pos < buf_len) {
- plen = buf_len - pos;
- if (plen >= SHA1_MAC_LEN) {
- if (hmac_sha1_vector(key, key_len, 3, addr, len,
- &buf[pos]))
- return -1;
- pos += SHA1_MAC_LEN;
- } else {
- if (hmac_sha1_vector(key, key_len, 3, addr, len,
- hash))
- return -1;
- os_memcpy(&buf[pos], hash, plen);
- break;
- }
- counter++;
- }
-
- return 0;
-}
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index 08e5a59..933cd81 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -22,6 +22,6 @@
int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
const char *label, const u8 *seed,
size_t seed_len, u8 *out, size_t outlen);
-int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen);
#endif /* SHA1_H */
diff --git a/src/crypto/sha256-prf.c b/src/crypto/sha256-prf.c
new file mode 100644
index 0000000..0da6d13
--- /dev/null
+++ b/src/crypto/sha256-prf.c
@@ -0,0 +1,64 @@
+/*
+ * SHA256-based PRF (IEEE 802.11r)
+ * Copyright (c) 2003-2007, 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 "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
+ * @key: Key for PRF
+ * @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 sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ u16 counter = 1;
+ size_t pos, plen;
+ u8 hash[SHA256_MAC_LEN];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 counter_le[2], length_le[2];
+
+ 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 * 8);
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ WPA_PUT_LE16(counter_le, counter);
+ if (plen >= SHA256_MAC_LEN) {
+ hmac_sha256_vector(key, key_len, 4, addr, len,
+ &buf[pos]);
+ pos += SHA256_MAC_LEN;
+ } else {
+ hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+}
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index 5c09ed1..b55e976 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -1,6 +1,6 @@
/*
* SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -21,9 +21,10 @@
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
* @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[32];
@@ -35,12 +36,13 @@
* Fixed limit on the number of fragments to avoid having to
* allocate memory (which could fail).
*/
- return;
+ return -1;
}
/* if key is longer than 64 bytes reset it to key = SHA256(key) */
if (key_len > 64) {
- sha256_vector(1, &key, &key_len, tk);
+ if (sha256_vector(1, &key, &key_len, tk) < 0)
+ return -1;
key = tk;
key_len = 32;
}
@@ -68,7 +70,8 @@
_addr[i + 1] = addr[i];
_len[i + 1] = len[i];
}
- sha256_vector(1 + num_elem, _addr, _len, mac);
+ if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0)
+ return -1;
os_memset(k_pad, 0, sizeof(k_pad));
os_memcpy(k_pad, key, key_len);
@@ -81,7 +84,7 @@
_len[0] = 64;
_addr[1] = mac;
_len[1] = SHA256_MAC_LEN;
- sha256_vector(2, _addr, _len, mac);
+ return sha256_vector(2, _addr, _len, mac);
}
@@ -91,61 +94,11 @@
* @key_len: Length of the key in bytes
* @data: Pointers to the data area
* @data_len: Length of the data area
- * @mac: Buffer for the hash (20 bytes)
+ * @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
*/
-void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac)
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
{
- hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
-}
-
-
-/**
- * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
- * @key: Key for PRF
- * @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 sha256_prf(const u8 *key, size_t key_len, const char *label,
- const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
-{
- u16 counter = 1;
- size_t pos, plen;
- u8 hash[SHA256_MAC_LEN];
- const u8 *addr[4];
- size_t len[4];
- u8 counter_le[2], length_le[2];
-
- 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 * 8);
- pos = 0;
- while (pos < buf_len) {
- plen = buf_len - pos;
- WPA_PUT_LE16(counter_le, counter);
- if (plen >= SHA256_MAC_LEN) {
- hmac_sha256_vector(key, key_len, 4, addr, len,
- &buf[pos]);
- pos += SHA256_MAC_LEN;
- } else {
- hmac_sha256_vector(key, key_len, 4, addr, len, hash);
- os_memcpy(&buf[pos], hash, plen);
- break;
- }
- counter++;
- }
+ return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 412fb60..fcac800 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -11,10 +11,10 @@
#define SHA256_MAC_LEN 32
-void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac);
-void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
- size_t data_len, u8 *mac);
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
void sha256_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 tls_prf_sha256(const u8 *secret, size_t secret_len,
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 990f6e6..b61e439 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -81,6 +81,7 @@
#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
+#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
/**
* struct tls_connection_params - Parameters for TLS connection
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index f2b541e..dfb63ad 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -711,6 +711,8 @@
"mode");
ERR_load_crypto_strings();
ERR_print_errors_fp(stderr);
+ os_free(tls_global);
+ tls_global = NULL;
return NULL;
} else
wpa_printf(MSG_INFO, "Running in FIPS mode");
@@ -719,6 +721,8 @@
if (conf && conf->fips_mode) {
wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
"supported");
+ os_free(tls_global);
+ tls_global = NULL;
return NULL;
}
#endif /* OPENSSL_FIPS */
@@ -1936,6 +1940,8 @@
wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
"to certificate store", __func__);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ conn->ca_cert_verify = 1;
+
return 0;
#else /* OPENSSL_NO_ENGINE */
@@ -2099,7 +2105,7 @@
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
os_free(passwd);
-
+
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
"verification");
@@ -2145,7 +2151,7 @@
os_free(passwd);
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-
+
if (!SSL_CTX_check_private_key(ssl_ctx)) {
tls_show_errors(MSG_INFO, __func__,
"Private key failed verification");
@@ -2307,6 +2313,11 @@
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
+#ifdef CONFIG_FIPS
+ wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+ "mode");
+ return -1;
+#else /* CONFIG_FIPS */
SSL *ssl;
if (conn == NULL || keys == NULL)
@@ -2324,6 +2335,7 @@
keys->server_random_len = SSL3_RANDOM_SIZE;
return 0;
+#endif /* CONFIG_FIPS */
}
@@ -2331,6 +2343,19 @@
const char *label, int server_random_first,
u8 *out, size_t out_len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+ SSL *ssl;
+ if (conn == NULL)
+ return -1;
+ if (server_random_first)
+ return -1;
+ ssl = conn->ssl;
+ if (SSL_export_keying_material(ssl, out, out_len, label,
+ os_strlen(label), NULL, 0, 0) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
+ return 0;
+ }
+#endif
return -1;
}
@@ -2763,6 +2788,13 @@
return -1;
}
+#ifdef SSL_OP_NO_TICKET
+ if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+ SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+ else
+ SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /* SSL_OP_NO_TICKET */
+
conn->flags = params->flags;
tls_get_errors(tls_ctx);
@@ -2798,6 +2830,13 @@
return -1;
}
+#ifdef SSL_OP_NO_TICKET
+ if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+ SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+ else
+ SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /* SSL_OP_NO_TICKET */
+
return 0;
}
@@ -2807,6 +2846,7 @@
{
const EVP_CIPHER *c;
const EVP_MD *h;
+ int md_size;
if (conn == NULL || conn->ssl == NULL ||
conn->ssl->enc_read_ctx == NULL ||
@@ -2820,9 +2860,20 @@
#else
h = conn->ssl->read_hash;
#endif
+ if (h)
+ md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ else if (conn->ssl->s3)
+ md_size = conn->ssl->s3->tmp.new_mac_secret_size;
+#endif
+ else
+ return -1;
+ wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+ "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+ EVP_CIPHER_iv_length(c));
return 2 * (EVP_CIPHER_key_length(c) +
- EVP_MD_size(h) +
+ md_size +
EVP_CIPHER_iv_length(c));
}
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
index 6df7160..5906527 100644
--- a/src/drivers/android_drv.h
+++ b/src/drivers/android_drv.h
@@ -14,8 +14,6 @@
#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
-#define WEXT_CSCAN_AMOUNT 9
-
#define MAX_SSID_LEN 32
#define MAX_DRV_CMD_SIZE 248
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 0aab61e..e9f926f 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -274,6 +274,15 @@
size_t num_filter_ssids;
/**
+ * filter_rssi - Filter by RSSI
+ *
+ * The driver may filter scan results in firmware to reduce host
+ * wakeups and thereby save power. Specify the RSSI threshold in s32
+ * dBm.
+ */
+ s32 filter_rssi;
+
+ /**
* p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
*
* When set, the driver is expected to remove rates 1, 2, 5.5, and 11
@@ -731,6 +740,11 @@
* This is used by driver which advertises this capability.
*/
int ap_max_inactivity;
+
+ /**
+ * disable_dgaf - Whether group-addressed frames are disabled
+ */
+ int disable_dgaf;
};
/**
@@ -751,6 +765,7 @@
#define WPA_DRIVER_CAPA_ENC_TKIP 0x00000004
#define WPA_DRIVER_CAPA_ENC_CCMP 0x00000008
#define WPA_DRIVER_CAPA_ENC_WEP128 0x00000010
+#define WPA_DRIVER_CAPA_ENC_GCMP 0x00000020
unsigned int enc;
#define WPA_DRIVER_AUTH_OPEN 0x00000001
@@ -817,6 +832,8 @@
#define WPA_DRIVER_FLAGS_AP_UAPSD 0x00400000
/* Driver supports inactivity timer in AP mode */
#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER 0x00800000
+/* Driver expects user space implementation of MLME in AP mode */
+#define WPA_DRIVER_FLAGS_AP_MLME 0x01000000
unsigned int flags;
int max_scan_ssids;
@@ -983,6 +1000,23 @@
TDLS_DISABLE
};
+enum wnm_oper {
+ WNM_SLEEP_ENTER_CONFIRM,
+ WNM_SLEEP_ENTER_FAIL,
+ WNM_SLEEP_EXIT_CONFIRM,
+ WNM_SLEEP_EXIT_FAIL,
+ WNM_SLEEP_TFS_REQ_IE_ADD, /* STA requests driver to add TFS req IE */
+ WNM_SLEEP_TFS_REQ_IE_NONE, /* STA requests empty TFS req IE */
+ WNM_SLEEP_TFS_REQ_IE_SET, /* AP requests driver to set TFS req IE for
+ * a STA */
+ WNM_SLEEP_TFS_RESP_IE_ADD, /* AP requests driver to add TFS resp IE
+ * for a STA */
+ WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */
+ WNM_SLEEP_TFS_RESP_IE_SET, /* AP requests driver to set TFS resp IE
+ * for a STA */
+ WNM_SLEEP_TFS_IE_DEL /* AP delete the TFS IE */
+};
+
/**
* struct wpa_signal_info - Information about channel signal quality
*/
@@ -1042,7 +1076,8 @@
* @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
+ * %WPA_ALG_GCMP);
* %WPA_ALG_NONE clears the key.
* @addr: Address of the peer STA (BSSID of the current AP when setting
* pairwise key in station mode), ff:ff:ff:ff:ff:ff for
@@ -1059,11 +1094,11 @@
* for Rx keys (in most cases, this is only used with broadcast
* keys and set to zero for unicast keys); %NULL if not set
* @seq_len: length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
+ * TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
* @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
* 8-byte Rx Mic Key
* @key_len: length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP: 16, IGTK: 16)
+ * TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
*
* Returns: 0 on success, -1 on failure
*
@@ -1568,9 +1603,9 @@
* Returns: 0 on success, -1 on failure
*
* This function is used to fetch the last used TSC/packet number for
- * a TKIP, CCMP, or BIP/IGTK key. It is mainly used with group keys, so
- * there is no strict requirement on implementing support for unicast
- * keys (i.e., addr != %NULL).
+ * a TKIP, CCMP, GCMP, or BIP/IGTK key. It is mainly used with group
+ * keys, so there is no strict requirement on implementing support for
+ * unicast keys (i.e., addr != %NULL).
*/
int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
int idx, u8 *seq);
@@ -1603,7 +1638,7 @@
int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
/**
- * read_sta_data - Fetch station data (AP only)
+ * read_sta_data - Fetch station data
* @priv: Private driver interface data
* @data: Buffer for returning station information
* @addr: MAC address of the station
@@ -2399,6 +2434,18 @@
int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
/**
+ * wnm_oper - Notify driver of the WNM frame reception
+ * @priv: Private driver interface data
+ * @oper: WNM operation. See %enum wnm_oper
+ * @peer: Destination (peer) MAC address
+ * @buf: Buffer for the driver to fill in (for getting IE)
+ * @buf_len: Return the len of buf
+ * Returns: 0 on success, negative (<0) on failure
+ */
+ int (*wnm_oper)(void *priv, enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len);
+
+ /**
* signal_poll - Get current connection information
* @priv: Private driver interface data
* @signal_info: Connection info structure
@@ -3006,7 +3053,14 @@
*
* Described in wpa_event_data.ch_switch
* */
- EVENT_CH_SWITCH
+ EVENT_CH_SWITCH,
+
+ /**
+ * EVENT_WNM - Request WNM operation
+ *
+ * This event can be used to request a WNM operation to be performed.
+ */
+ EVENT_WNM
};
@@ -3209,6 +3263,24 @@
} tdls;
/**
+ * struct wnm - Data for EVENT_WNM
+ */
+ struct wnm {
+ u8 addr[ETH_ALEN];
+ enum {
+ WNM_OPER_SLEEP,
+ } oper;
+ enum {
+ WNM_SLEEP_ENTER,
+ WNM_SLEEP_EXIT
+ } sleep_action;
+ int sleep_intval;
+ u16 reason_code;
+ u8 *buf;
+ u16 buf_len;
+ } wnm;
+
+ /**
* struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
*
* During FT (IEEE 802.11r) authentication sequence, the driver is
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 73898d3..5f2e675 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -14,6 +14,12 @@
#include <sys/ioctl.h>
#include "common.h"
+#include "eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "l2_packet/l2_packet.h"
+#include "p2p/p2p.h"
+
+#include "common.h"
#ifndef _BYTE_ORDER
#ifdef WORDS_BIGENDIAN
#define _BYTE_ORDER _BIG_ENDIAN
@@ -318,8 +324,7 @@
}
#endif /* CONFIG_IEEE80211W */
- wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
- __func__, params->rsn_preauth);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
printf("Unable to set RSN capabilities to 0x%x\n", v);
return -1;
@@ -837,7 +842,88 @@
}
#endif /* CONFIG_IEEE80211R */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
+#ifdef CONFIG_HS20
+static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct atheros_driver_data *drv = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ union wpa_event_data event;
+
+ /* Send the Action frame for HS20 processing */
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
+ sizeof(mgmt->u.action.u.public_action))
+ return;
+
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
+ mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+ return;
+
+ wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
+
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = (const u8 *) mgmt;
+ event.rx_mgmt.frame_len = len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
+}
+#endif /* CONFIG_HS20 */
+
+#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct atheros_driver_data *drv = ctx;
+ union wpa_event_data event;
+ const struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ u16 stype;
+
+ /* Do 11R processing for WNM ACTION frames */
+ if (len < IEEE80211_HDRLEN)
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
+ return;
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
+ (int) len);
+
+ if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
+ __func__);
+ return;
+ }
+
+ switch (stype) {
+ case WLAN_FC_STYPE_ACTION:
+ if (&mgmt->u.action.category > buf + len)
+ break;
+ os_memset(&event, 0, sizeof(event));
+ event.rx_action.da = mgmt->da;
+ event.rx_action.sa = mgmt->sa;
+ event.rx_action.bssid = mgmt->bssid;
+ event.rx_action.category = mgmt->u.action.category;
+ event.rx_action.data = &mgmt->u.action.category;
+ event.rx_action.len = buf + len - event.rx_action.data;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
+ break;
+ default:
+ break;
+ }
+}
+#endif /* CONFIG_IEEE80211V */
+
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211V)
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -847,6 +933,12 @@
#ifdef CONFIG_IEEE80211R
atheros_raw_recv_11r(ctx, src_addr, buf, len);
#endif /* CONFIG_IEEE80211R */
+#if defined(CONFIG_IEEE80211V) && !defined(CONFIG_IEEE80211R)
+ atheros_raw_recv_11v(ctx, src_addr, buf, len);
+#endif /* CONFIG_IEEE80211V */
+#ifdef CONFIG_HS20
+ atheros_raw_recv_hs20(ctx, src_addr, buf, len);
+#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
@@ -862,8 +954,15 @@
#endif /* CONFIG_WPS */
#ifdef CONFIG_IEEE80211R
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
- IEEE80211_FILTER_TYPE_AUTH);
+ IEEE80211_FILTER_TYPE_AUTH |
+ IEEE80211_FILTER_TYPE_ACTION);
#endif
+#ifdef CONFIG_IEEE80211V
+ filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_IEEE80211V */
+#ifdef CONFIG_HS20
+ filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
+#endif /* CONFIG_HS20 */
if (filt.app_filterype) {
ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
sizeof(struct ieee80211req_set_filter));
@@ -1165,8 +1264,8 @@
*/
wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
#endif /* CONFIG_WPS */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
-#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
/*
* Atheros driver uses a hack to pass Probe Request frames as a
@@ -1175,50 +1274,136 @@
* Format: "Manage.prob_req <frame len>" | zero padding | frame
*/
int len = atoi(custom + 16);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
"length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
} else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
int len = atoi(custom + 17);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
"assoc_req/auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
} else if (strncmp(custom, "Manage.action ", 14) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
int len = atoi(custom + 14);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
"assoc_req/auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
} else if (strncmp(custom, "Manage.auth ", 12) == 0) {
/* Format: "Manage.auth <frame len>" | zero padding | frame
*/
int len = atoi(custom + 12);
- if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
"assoc_req/auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
- (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+ (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
}
}
+/*
+* Handle size of data problem. WEXT only allows data of 256 bytes for custom
+* events, and p2p data can be much bigger. So the athr driver sends a small
+* event telling me to collect the big data with an ioctl.
+* On the first event, send all pending events to supplicant.
+*/
+static void fetch_pending_big_events(struct atheros_driver_data *drv)
+{
+ union wpa_event_data event;
+ const struct ieee80211_mgmt *mgmt;
+ u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */
+ u16 fc, stype;
+ struct iwreq iwr;
+ size_t data_len;
+ u32 freq, frame_type;
+
+ while (1) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.data.pointer = (void *) tbuf;
+ iwr.u.data.length = sizeof(tbuf);
+ iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME;
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr)
+ < 0) {
+ if (errno == ENOSPC) {
+ wpa_printf(MSG_DEBUG, "%s:%d exit",
+ __func__, __LINE__);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM["
+ "P2P_FETCH_FRAME] failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+ data_len = iwr.u.data.length;
+ wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data",
+ (u8 *) tbuf, data_len);
+ if (data_len < sizeof(freq) + sizeof(frame_type) + 24) {
+ wpa_printf(MSG_DEBUG, "athr: frame too short");
+ continue;
+ }
+ os_memcpy(&freq, tbuf, sizeof(freq));
+ os_memcpy(&frame_type, &tbuf[sizeof(freq)],
+ sizeof(frame_type));
+ mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)];
+ data_len -= sizeof(freq) + sizeof(frame_type);
+
+ if (frame_type == IEEE80211_EV_RX_MGMT) {
+ fc = le_to_host16(mgmt->frame_control);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u "
+ "freq=%u len=%u", stype, freq, (int) data_len);
+
+ if (stype == WLAN_FC_STYPE_ACTION) {
+ os_memset(&event, 0, sizeof(event));
+ event.rx_mgmt.frame = (const u8 *) mgmt;
+ event.rx_mgmt.frame_len = data_len;
+ wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT,
+ &event);
+ continue;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
+ __func__, frame_type);
+ continue;
+ }
+ }
+}
+
+static void
+atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
+ int opcode, char *buf, int len)
+{
+ switch (opcode) {
+ case IEEE80211_EV_RX_MGMT:
+ wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
+ fetch_pending_big_events(drv);
+ break;
+ default:
+ break;
+ }
+}
+
static void
atheros_wireless_event_wireless(struct atheros_driver_data *drv,
char *data, int len)
@@ -1274,8 +1459,15 @@
return; /* XXX */
memcpy(buf, custom, iwe->u.data.length);
buf[iwe->u.data.length] = '\0';
- atheros_wireless_event_wireless_custom(
- drv, buf, buf + iwe->u.data.length);
+
+ if (iwe->u.data.flags != 0) {
+ atheros_wireless_event_atheros_custom(
+ drv, (int) iwe->u.data.flags,
+ buf, len);
+ } else {
+ atheros_wireless_event_wireless_custom(
+ drv, buf, buf + iwe->u.data.length);
+ }
free(buf);
break;
}
@@ -1709,6 +1901,221 @@
#endif /* CONFIG_IEEE80211R */
+/* Use only to set a big param, get will not work. */
+static int
+set80211big(struct atheros_driver_data *drv, int op, const void *data, int len)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.data.pointer = (void *) data;
+ iwr.u.data.length = len;
+ iwr.u.data.flags = op;
+ wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x",
+ __func__, op, op, athr_get_param_name(op), len);
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d "
+ "value=0x%x,0x%x failed: %d (%s)",
+ __func__, op, athr_get_ioctl_name(op), iwr.u.mode,
+ iwr.u.mode, iwr.u.data.length,
+ iwr.u.data.flags, errno, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+
+static int atheros_send_action(void *priv, unsigned int freq,
+ unsigned int wait,
+ const u8 *dst, const u8 *src,
+ const u8 *bssid,
+ const u8 *data, size_t data_len, int no_cck)
+{
+ struct atheros_driver_data *drv = priv;
+ struct ieee80211_p2p_send_action *act;
+ int res;
+
+ act = os_zalloc(sizeof(*act) + data_len);
+ if (act == NULL)
+ return -1;
+ act->freq = freq;
+ os_memcpy(act->dst_addr, dst, ETH_ALEN);
+ os_memcpy(act->src_addr, src, ETH_ALEN);
+ os_memcpy(act->bssid, bssid, ETH_ALEN);
+ os_memcpy(act + 1, data, data_len);
+ wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src="
+ MACSTR ", bssid=" MACSTR,
+ __func__, act->freq, wait, MAC2STR(act->dst_addr),
+ MAC2STR(act->src_addr), MAC2STR(act->bssid));
+ wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act));
+ wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len);
+
+ res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION,
+ act, sizeof(*act) + data_len);
+ os_free(act);
+ return res;
+}
+
+
+#ifdef CONFIG_IEEE80211V
+static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
+ u8 *ie, u16 *len, enum wnm_oper oper)
+{
+#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */
+ u8 buf[IEEE80211_APPIE_MAX];
+ struct ieee80211req_getset_appiebuf *tfs_ie;
+ u16 val;
+
+ wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
+ drv->iface, oper, MAC2STR(peer));
+
+ switch (oper) {
+ case WNM_SLEEP_TFS_REQ_IE_SET:
+ if (*len > IEEE80211_APPIE_MAX -
+ sizeof(struct ieee80211req_getset_appiebuf)) {
+ wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
+ return -1;
+ }
+ tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+ tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
+
+ /* Command header for driver */
+ os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+ val = oper;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+ val = *len;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+ /* copy the ie */
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
+
+ if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+ IEEE80211_APPIE_MAX)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+ "%s", __func__, strerror(errno));
+ return -1;
+ }
+ break;
+ case WNM_SLEEP_TFS_RESP_IE_ADD:
+ tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+ tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+ sizeof(struct ieee80211req_getset_appiebuf);
+ /* Command header for driver */
+ os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+ val = oper;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+ val = 0;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
+ IEEE80211_APPIE_MAX)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
+ "%s", __func__, strerror(errno));
+ return -1;
+ }
+
+ *len = tfs_ie->app_buflen;
+ os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
+ wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
+ *len);
+ break;
+ case WNM_SLEEP_TFS_RESP_IE_NONE:
+ *len = 0;
+ break;
+ case WNM_SLEEP_TFS_IE_DEL:
+ tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
+ tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
+ sizeof(struct ieee80211req_getset_appiebuf);
+ /* Command header for driver */
+ os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
+ val = oper;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
+ val = 0;
+ os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
+
+ if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
+ IEEE80211_APPIE_MAX)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
+ "%s", __func__, strerror(errno));
+ return -1;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
+ break;
+ }
+
+ return 0;
+}
+
+
+static int atheros_wnm_sleep(struct atheros_driver_data *drv,
+ const u8 *peer, enum wnm_oper oper)
+{
+ u8 *data, *pos;
+ size_t dlen;
+ int ret;
+ u16 val;
+
+ wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
+ oper, MAC2STR(peer));
+
+ dlen = ETH_ALEN + 2 + 2;
+ data = os_malloc(dlen);
+ if (data == NULL)
+ return -1;
+
+ /* Command header for driver */
+ pos = data;
+ os_memcpy(pos, peer, ETH_ALEN);
+ pos += ETH_ALEN;
+
+ val = oper;
+ os_memcpy(pos, &val, 2);
+ pos += 2;
+
+ val = 0;
+ os_memcpy(pos, &val, 2);
+
+ ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
+
+ os_free(data);
+
+ return ret;
+}
+
+
+static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len)
+{
+ struct atheros_driver_data *drv = priv;
+
+ switch (oper) {
+ case WNM_SLEEP_ENTER_CONFIRM:
+ case WNM_SLEEP_ENTER_FAIL:
+ case WNM_SLEEP_EXIT_CONFIRM:
+ case WNM_SLEEP_EXIT_FAIL:
+ return atheros_wnm_sleep(drv, peer, oper);
+ case WNM_SLEEP_TFS_REQ_IE_SET:
+ case WNM_SLEEP_TFS_RESP_IE_ADD:
+ case WNM_SLEEP_TFS_RESP_IE_NONE:
+ case WNM_SLEEP_TFS_IE_DEL:
+ return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
+ default:
+ wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
+ oper);
+ return -1;
+ }
+}
+#endif /* CONFIG_IEEE80211V */
+
+
const struct wpa_driver_ops wpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = atheros_init,
@@ -1739,4 +2146,8 @@
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
#endif /* CONFIG_IEEE80211R */
+ .send_action = atheros_send_action,
+#ifdef CONFIG_IEEE80211V
+ .wnm_oper = atheros_wnm_oper,
+#endif /* CONFIG_IEEE80211V */
};
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 67abb67..a2b34c1 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -1328,8 +1328,8 @@
result->ie_len = pos - (u8 *)(result + 1);
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(result);
return;
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 81856aa..418cf1a 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -78,6 +78,7 @@
E2S(DRIVER_CLIENT_POLL_OK);
E2S(EAPOL_TX_STATUS);
E2S(CH_SWITCH);
+ E2S(WNM);
}
return "UNKNOWN";
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 185ed4f..b9e096c 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -858,7 +858,7 @@
os_free(b);
return NULL;
}
- results->res = os_zalloc(count * sizeof(struct wpa_scan_res *));
+ results->res = os_calloc(count, sizeof(struct wpa_scan_res *));
if (results->res == NULL) {
os_free(results);
os_free(b);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e099a67..a9e6139 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -2386,7 +2386,7 @@
struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
struct wiphy_info_data *info = arg;
int p2p_go_supported = 0, p2p_client_supported = 0;
- int p2p_concurrent = 0;
+ int p2p_concurrent = 0, p2p_multichan_concurrent = 0;
int auth_supported = 0, connect_supported = 0;
struct wpa_driver_capa *capa = info->capa;
static struct nla_policy
@@ -2487,6 +2487,8 @@
if (combination_has_p2p && combination_has_mgd) {
p2p_concurrent = 1;
+ if (nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]) > 1)
+ p2p_multichan_concurrent = 1;
break;
}
@@ -2554,6 +2556,13 @@
"interface (driver advertised support)");
capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+
+ if (p2p_multichan_concurrent) {
+ wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+ "concurrent (driver advertised support)");
+ capa->flags |=
+ WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+ }
}
if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
@@ -2566,9 +2575,8 @@
WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
}
}
-#ifndef ANDROID_P2P
+
if (tb[NL80211_ATTR_DEVICE_AP_SME])
-#endif
info->device_ap_sme = 1;
if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
@@ -2646,11 +2654,17 @@
drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-#ifndef ANDROID_P2P
- if (!info.device_ap_sme)
-#endif
+
+ if (!info.device_ap_sme) {
drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+ /*
+ * No AP SME is currently assumed to also indicate no AP MLME
+ * in the driver/firmware.
+ */
+ drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+ }
+
drv->device_ap_sme = info.device_ap_sme;
drv->poll_command_supported = info.poll_command_supported;
drv->data_tx_status = info.data_tx_status;
@@ -3487,6 +3501,83 @@
}
+static struct nl_msg *
+nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
+ struct wpa_driver_scan_params *params)
+{
+ struct nl_msg *msg;
+ int err;
+ size_t i;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ nl80211_cmd(drv, msg, 0, cmd);
+
+ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) < 0)
+ goto fail;
+
+ if (params->num_ssids) {
+ struct nl_msg *ssids = nlmsg_alloc();
+ if (ssids == NULL)
+ goto fail;
+ for (i = 0; i < params->num_ssids; i++) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
+ params->ssids[i].ssid,
+ params->ssids[i].ssid_len);
+ if (nla_put(ssids, i + 1, params->ssids[i].ssid_len,
+ params->ssids[i].ssid) < 0) {
+ nlmsg_free(ssids);
+ goto fail;
+ }
+ }
+ err = nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+ nlmsg_free(ssids);
+ if (err < 0)
+ goto fail;
+ }
+
+ if (params->extra_ies) {
+ wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+ params->extra_ies, params->extra_ies_len);
+ if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+ params->extra_ies) < 0)
+ goto fail;
+ }
+
+ if (params->freqs) {
+ struct nl_msg *freqs = nlmsg_alloc();
+ if (freqs == NULL)
+ goto fail;
+ for (i = 0; params->freqs[i]; i++) {
+ wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+ "MHz", params->freqs[i]);
+ if (nla_put_u32(freqs, i + 1, params->freqs[i]) < 0) {
+ nlmsg_free(freqs);
+ goto fail;
+ }
+ }
+ err = nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES,
+ freqs);
+ nlmsg_free(freqs);
+ if (err < 0)
+ goto fail;
+ }
+
+ os_free(drv->filter_ssids);
+ drv->filter_ssids = params->filter_ssids;
+ params->filter_ssids = NULL;
+ drv->num_filter_ssids = params->num_filter_ssids;
+
+ return msg;
+
+fail:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
/**
* wpa_driver_nl80211_scan - Request the driver to initiate scan
* @priv: Pointer to private driver data from wpa_driver_nl80211_init()
@@ -3498,62 +3589,22 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0, timeout;
- struct nl_msg *msg, *ssids, *freqs, *rates;
- size_t i;
+ int ret = -1, timeout;
+ struct nl_msg *msg, *rates = NULL;
drv->scan_for_auth = 0;
- msg = nlmsg_alloc();
- ssids = nlmsg_alloc();
- freqs = nlmsg_alloc();
- rates = nlmsg_alloc();
- if (!msg || !ssids || !freqs || !rates) {
- nlmsg_free(msg);
- nlmsg_free(ssids);
- nlmsg_free(freqs);
- nlmsg_free(rates);
+ msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params);
+ if (!msg)
return -1;
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid);
- }
- if (params->num_ssids)
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
- if (params->extra_ies) {
- wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
- params->extra_ies, params->extra_ies_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies);
- }
-
- if (params->freqs) {
- for (i = 0; params->freqs[i]; i++) {
- wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
- "MHz", params->freqs[i]);
- NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
- }
- nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
- }
if (params->p2p_probe) {
wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+ rates = nlmsg_alloc();
+ if (rates == NULL)
+ goto nla_put_failure;
+
/*
* Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
* by masking out everything else apart from the OFDM rates 6,
@@ -3562,7 +3613,9 @@
*/
NLA_PUT(rates, NL80211_BAND_2GHZ, 8,
"\x0c\x12\x18\x24\x30\x48\x60\x6c");
- nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates);
+ if (nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, rates) <
+ 0)
+ goto nla_put_failure;
NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
}
@@ -3615,9 +3668,7 @@
drv, drv->ctx);
nla_put_failure:
- nlmsg_free(ssids);
nlmsg_free(msg);
- nlmsg_free(freqs);
nlmsg_free(rates);
return ret;
}
@@ -3636,8 +3687,10 @@
{
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
- int ret = 0;
- struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+ int ret = -1;
+ struct nl_msg *msg;
+ struct nl_msg *match_set_ssid = NULL, *match_sets = NULL;
+ struct nl_msg *match_set_rssi = NULL;
size_t i;
#ifdef ANDROID
@@ -3645,30 +3698,18 @@
return android_pno_start(bss, params);
#endif /* ANDROID */
- msg = nlmsg_alloc();
- ssids = nlmsg_alloc();
- freqs = nlmsg_alloc();
- if (!msg || !ssids || !freqs) {
- nlmsg_free(msg);
- nlmsg_free(ssids);
- nlmsg_free(freqs);
- return -1;
- }
-
- os_free(drv->filter_ssids);
- drv->filter_ssids = params->filter_ssids;
- params->filter_ssids = NULL;
- drv->num_filter_ssids = params->num_filter_ssids;
-
- nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
-
- NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params);
+ if (!msg)
+ goto nla_put_failure;
NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
- if (drv->num_filter_ssids &&
- (int) drv->num_filter_ssids <= drv->capa.max_match_sets) {
+ if ((drv->num_filter_ssids &&
+ (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+ params->filter_rssi) {
match_sets = nlmsg_alloc();
+ if (match_sets == NULL)
+ goto nla_put_failure;
for (i = 0; i < drv->num_filter_ssids; i++) {
wpa_hexdump_ascii(MSG_MSGDUMP,
@@ -3677,45 +3718,35 @@
drv->filter_ssids[i].ssid_len);
match_set_ssid = nlmsg_alloc();
- nla_put(match_set_ssid,
+ if (match_set_ssid == NULL)
+ goto nla_put_failure;
+ NLA_PUT(match_set_ssid,
NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
drv->filter_ssids[i].ssid_len,
drv->filter_ssids[i].ssid);
- nla_put_nested(match_sets, i + 1, match_set_ssid);
-
- nlmsg_free(match_set_ssid);
+ if (nla_put_nested(match_sets, i + 1, match_set_ssid) <
+ 0)
+ goto nla_put_failure;
}
- nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
- match_sets);
- nlmsg_free(match_sets);
- }
-
- for (i = 0; i < params->num_ssids; i++) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
- params->ssids[i].ssid,
- params->ssids[i].ssid_len);
- NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
- params->ssids[i].ssid);
- }
- if (params->num_ssids)
- nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
-
- if (params->extra_ies) {
- wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
- params->extra_ies, params->extra_ies_len);
- NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
- params->extra_ies);
- }
-
- if (params->freqs) {
- for (i = 0; params->freqs[i]; i++) {
- wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
- "MHz", params->freqs[i]);
- NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+ if (params->filter_rssi) {
+ match_set_rssi = nlmsg_alloc();
+ if (match_set_rssi == NULL)
+ goto nla_put_failure;
+ NLA_PUT_U32(match_set_rssi,
+ NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+ params->filter_rssi);
+ wpa_printf(MSG_MSGDUMP,
+ "nl80211: Sched scan RSSI filter %d dBm",
+ params->filter_rssi);
+ if (nla_put_nested(match_sets, 0, match_set_rssi) < 0)
+ goto nla_put_failure;
}
- nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+
+ if (nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+ match_sets) < 0)
+ goto nla_put_failure;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -3733,9 +3764,10 @@
"scan interval %d msec", ret, interval);
nla_put_failure:
- nlmsg_free(ssids);
+ nlmsg_free(match_set_ssid);
+ nlmsg_free(match_sets);
+ nlmsg_free(match_set_rssi);
nlmsg_free(msg);
- nlmsg_free(freqs);
return ret;
}
@@ -3983,8 +4015,8 @@
return NL_SKIP;
}
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
return NL_SKIP;
@@ -4187,6 +4219,10 @@
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_ALG_GCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4327,6 +4363,9 @@
case WPA_ALG_CCMP:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_ALG_GCMP:
+ NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_ALG_IGTK:
NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
WLAN_CIPHER_SUITE_AES_CMAC);
@@ -4779,7 +4818,9 @@
return NL_SKIP;
nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
- mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
+ mode = os_realloc_array(phy_info->modes,
+ *phy_info->num_modes + 1,
+ sizeof(*mode));
if (!mode)
return NL_SKIP;
phy_info->modes = mode;
@@ -4838,7 +4879,8 @@
mode->num_channels++;
}
- mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
+ mode->channels = os_calloc(mode->num_channels,
+ sizeof(struct hostapd_channel_data));
if (!mode->channels)
return NL_SKIP;
@@ -4900,7 +4942,7 @@
mode->num_rates++;
}
- mode->rates = os_zalloc(mode->num_rates * sizeof(int));
+ mode->rates = os_calloc(mode->num_rates, sizeof(int));
if (!mode->rates)
return NL_SKIP;
@@ -4945,7 +4987,7 @@
if (mode11g_idx < 0)
return modes; /* 2.4 GHz band not supported at all */
- nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+ nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
if (nmodes == NULL)
return modes; /* Could not add 802.11b mode */
@@ -5459,6 +5501,8 @@
num_suites = 0;
if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+ if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
+ suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
@@ -5475,6 +5519,10 @@
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_CCMP);
break;
+ case WPA_CIPHER_GCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+ WLAN_CIPHER_SUITE_GCMP);
+ break;
case WPA_CIPHER_TKIP:
NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
WLAN_CIPHER_SUITE_TKIP);
@@ -5645,7 +5693,8 @@
NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
(params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
WMM_QOSINFO_STA_SP_MASK);
- nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+ if (nla_put_nested(msg, NL80211_ATTR_STA_WME, wme) < 0)
+ goto nla_put_failure;
}
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6748,6 +6797,9 @@
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6769,6 +6821,9 @@
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6911,6 +6966,9 @@
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -6933,6 +6991,9 @@
case CIPHER_CCMP:
cipher = WLAN_CIPHER_SUITE_CCMP;
break;
+ case CIPHER_GCMP:
+ cipher = WLAN_CIPHER_SUITE_GCMP;
+ break;
case CIPHER_TKIP:
default:
cipher = WLAN_CIPHER_SUITE_TKIP;
@@ -7086,6 +7147,11 @@
return ret;
}
+ if (is_p2p_interface(nlmode))
+ nl80211_disable_11b_rates(drv, drv->ifindex, 1);
+ else if (drv->disabled_11b_rates)
+ nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+
if (is_ap_interface(nlmode)) {
nl80211_mgmt_unsubscribe(bss, "start AP");
/* Setup additional AP mode functionality if needed */
@@ -7325,6 +7391,8 @@
return -ENOBUFS;
}
+#endif /* HOSTAPD || CONFIG_AP */
+
static int get_sta_handler(struct nl_msg *msg, void *arg)
{
@@ -7405,6 +7473,8 @@
}
+#if defined(HOSTAPD) || defined(CONFIG_AP)
+
static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
int cw_min, int cw_max, int burst_time)
{
@@ -7588,8 +7658,8 @@
else
old = NULL;
- drv->if_indices = os_realloc(old,
- sizeof(int) * (drv->num_if_indices + 1));
+ drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
+ sizeof(int));
if (!drv->if_indices) {
if (!old)
drv->if_indices = drv->default_if_indices;
@@ -7653,7 +7723,10 @@
bridge_ifname, name) < 0)
return -1;
}
- linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
+ if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
+ "interface %s up", name);
+ }
return i802_set_sta_vlan(priv, addr, name, 0);
} else {
i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -8379,7 +8452,9 @@
if (ret) {
wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
"(%s)", ret, strerror(-ret));
- }
+ } else
+ drv->disabled_11b_rates = disabled;
+
return ret;
nla_put_failure:
@@ -8472,6 +8547,7 @@
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg, *cqm = NULL;
+ int ret = -1;
wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
"hysteresis=%d", threshold, hysteresis);
@@ -8486,20 +8562,20 @@
cqm = nlmsg_alloc();
if (cqm == NULL)
- return -1;
+ goto nla_put_failure;
NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
- nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
+ if (nla_put_nested(msg, NL80211_ATTR_CQM, cqm) < 0)
+ goto nla_put_failure;
- if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
- return 0;
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
msg = NULL;
nla_put_failure:
nlmsg_free(cqm);
nlmsg_free(msg);
- return -1;
+ return ret;
}
@@ -9136,7 +9212,6 @@
#if defined(HOSTAPD) || defined(CONFIG_AP)
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
- .read_sta_data = i802_read_sta_data,
.get_inact_sec = i802_get_inact_sec,
.sta_clear_stats = i802_sta_clear_stats,
.set_rts = i802_set_rts,
@@ -9146,6 +9221,7 @@
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
#endif /* HOSTAPD || CONFIG_AP */
+ .read_sta_data = i802_read_sta_data,
.set_freq = i802_set_freq,
.send_action = wpa_driver_nl80211_send_action,
.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index c8916f0..9481cbf 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -152,7 +152,7 @@
return NULL;
}
- results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
+ results->res = os_calloc(num, sizeof(struct wpa_scan_res *));
if (results->res == NULL) {
os_free(results);
os_free(buf);
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index f011651..e7bf195 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -1478,7 +1478,7 @@
if (res == NULL)
return NULL;
- res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
+ res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
if (res->res == NULL) {
os_free(res);
return NULL;
@@ -2570,15 +2570,14 @@
*num_modes = 3;
*flags = 0;
- modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+ modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes));
if (modes == NULL)
return NULL;
modes[0].mode = HOSTAPD_MODE_IEEE80211G;
modes[0].num_channels = 11;
modes[0].num_rates = 12;
- modes[0].channels =
- os_zalloc(11 * sizeof(struct hostapd_channel_data));
- modes[0].rates = os_zalloc(modes[0].num_rates * sizeof(int));
+ modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+ modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int));
if (modes[0].channels == NULL || modes[0].rates == NULL)
goto fail;
for (i = 0; i < 11; i++) {
@@ -2602,9 +2601,8 @@
modes[1].mode = HOSTAPD_MODE_IEEE80211B;
modes[1].num_channels = 11;
modes[1].num_rates = 4;
- modes[1].channels =
- os_zalloc(11 * sizeof(struct hostapd_channel_data));
- modes[1].rates = os_zalloc(modes[1].num_rates * sizeof(int));
+ modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
+ modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int));
if (modes[1].channels == NULL || modes[1].rates == NULL)
goto fail;
for (i = 0; i < 11; i++) {
@@ -2620,8 +2618,8 @@
modes[2].mode = HOSTAPD_MODE_IEEE80211A;
modes[2].num_channels = 1;
modes[2].num_rates = 8;
- modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
- modes[2].rates = os_zalloc(modes[2].num_rates * sizeof(int));
+ modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data));
+ modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int));
if (modes[2].channels == NULL || modes[2].rates == NULL)
goto fail;
modes[2].channels[0].chan = 60;
@@ -2822,17 +2820,19 @@
static int wpa_driver_test_p2p_find(void *priv, unsigned int timeout, int type)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
if (!drv->p2p)
return -1;
- return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL);
+ return p2p_find(drv->p2p, timeout, type, 0, NULL, NULL, 0);
}
static int wpa_driver_test_p2p_stop_find(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
if (!drv->p2p)
return -1;
@@ -2843,7 +2843,8 @@
static int wpa_driver_test_p2p_listen(void *priv, unsigned int timeout)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(timeout=%u)", __func__, timeout);
if (!drv->p2p)
return -1;
@@ -2857,7 +2858,8 @@
unsigned int force_freq,
int persistent_group)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR " wps_method=%d "
"go_intent=%d "
"own_interface_addr=" MACSTR " force_freq=%u "
@@ -2874,7 +2876,8 @@
static int wpa_driver_test_wps_success_cb(void *priv, const u8 *peer_addr)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s(peer_addr=" MACSTR ")",
__func__, MAC2STR(peer_addr));
if (!drv->p2p)
@@ -2886,7 +2889,8 @@
static int wpa_driver_test_p2p_group_formation_failed(void *priv)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
if (!drv->p2p)
return -1;
@@ -2898,7 +2902,8 @@
static int wpa_driver_test_p2p_set_params(void *priv,
const struct p2p_params *params)
{
- struct wpa_driver_test_data *drv = priv;
+ struct test_driver_bss *dbss = priv;
+ struct wpa_driver_test_data *drv = dbss->drv;
wpa_printf(MSG_DEBUG, "%s", __func__);
if (!drv->p2p)
return -1;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 068e416..bd37ca1 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -40,10 +40,7 @@
static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg);
-#ifdef ANDROID
-extern int wpa_driver_wext_combo_scan(void *priv,
- struct wpa_driver_scan_params *params);
-#endif
+
int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
int idx, u32 value)
@@ -481,19 +478,10 @@
drv->assoc_req_ies = NULL;
os_free(drv->assoc_resp_ies);
drv->assoc_resp_ies = NULL;
-#ifdef ANDROID
- if (!drv->skip_disconnect) {
- drv->skip_disconnect = 1;
-#endif
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC,
NULL);
-#ifdef ANDROID
- }
-#endif
+
} else {
-#ifdef ANDROID
- drv->skip_disconnect = 0;
-#endif
wpa_driver_wext_event_assoc_ies(drv);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC,
NULL);
@@ -875,7 +863,6 @@
#ifdef ANDROID
drv->errors = 0;
drv->driver_is_started = TRUE;
- drv->skip_disconnect = 0;
drv->bgscan_enabled = 0;
#endif /* ANDROID */
@@ -1039,13 +1026,6 @@
const u8 *ssid = params->ssids[0].ssid;
size_t ssid_len = params->ssids[0].ssid_len;
-#ifdef ANDROID
- if (drv->capa.max_scan_ssids > 1) {
- ret = wpa_driver_wext_combo_scan(priv, params);
- goto scan_out;
- }
-#endif
-
if (ssid_len > IW_ESSID_MAX_SIZE) {
wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
__FUNCTION__, (unsigned long) ssid_len);
@@ -1071,9 +1051,6 @@
ret = -1;
}
-#ifdef ANDROID
-scan_out:
-#endif
/* Not all drivers generate "scan completed" wireless event, so try to
* read results after a timeout. */
timeout = 10;
@@ -1437,8 +1414,8 @@
if (data->ie)
os_memcpy(pos, data->ie, data->ie_len);
- tmp = os_realloc(res->res,
- (res->num + 1) * sizeof(struct wpa_scan_res *));
+ tmp = os_realloc_array(res->res, res->num + 1,
+ sizeof(struct wpa_scan_res *));
if (tmp == NULL) {
os_free(r);
return;
@@ -1608,11 +1585,7 @@
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
-#ifdef ANDROID
- drv->capa.max_scan_ssids = WEXT_CSCAN_AMOUNT;
-#else
drv->capa.max_scan_ssids = 1;
-#endif
wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
"flags 0x%x",
@@ -2084,9 +2057,7 @@
int value;
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-#ifdef ANDROID
- drv->skip_disconnect = 0;
-#endif
+
if (drv->cfg80211) {
/*
* Stop cfg80211 from trying to associate before we are done
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index 7e0b28b..c4a5bc9 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -48,7 +48,6 @@
#ifdef ANDROID
int errors;
int driver_is_started;
- int skip_disconnect;
int bgscan_enabled;
#endif /* ANDROID */
};
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 0cc81f9..c7a98d3 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -30,7 +30,7 @@
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -142,6 +142,28 @@
DRV_OBJS += ../src/drivers/rfkill.o
endif
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ endif
+
+ ifdef CONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
+ DRV_LIBS += -lnl-route
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+ endif
+endif
+endif
+endif
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 1d7129c..23fcbb7 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -30,7 +30,7 @@
ifdef CONFIG_LIBNL32
DRV_LIBS += -lnl-3
DRV_LIBS += -lnl-genl-3
- DRV_CFLAGS += -DCONFIG_LIBNL20
+ DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3
else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
@@ -146,6 +146,29 @@
DRV_CFLAGS += -DCONFIG_DRIVER_CUSTOM
endif
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+ifdef CONFIG_LIBNL32
+ DRV_LIBS += -lnl-3
+ DRV_LIBS += -lnl-genl-3
+ DRV_LIBS += -lnl-route-3
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+ ifdef CONFIG_LIBNL_TINY
+ DRV_LIBS += -lnl-tiny
+ else
+ DRV_LIBS += -lnl
+ endif
+
+ ifdef CONFIG_LIBNL20
+ DRV_LIBS += -lnl-genl
+ DRV_LIBS += -lnl-route
+ DRV_CFLAGS += -DCONFIG_LIBNL20
+ endif
+endif
+endif
+endif
+
##### COMMON VARS
DRV_BOTH_CFLAGS := $(DRV_CFLAGS) $(DRV_WPA_CFLAGS) $(DRV_AP_CFLAGS)
DRV_WPA_CFLAGS += $(DRV_CFLAGS)
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 940b69a..4380428 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -45,8 +45,9 @@
if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
ret = errno ? -errno : -999;
- wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
- ifname, strerror(errno));
+ wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
+ "%s",
+ ifname, dev_up ? "UP" : "DOWN", strerror(errno));
return ret;
}
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 74cc55c..2f38788 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -771,6 +771,9 @@
* @NL80211_ATTR_IFNAME: network interface name
* @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
*
+ * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices
+ * that don't have a netdev (u64)
+ *
* @NL80211_ATTR_MAC: MAC address (various uses)
*
* @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
@@ -1242,6 +1245,12 @@
* @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds
* or 0 to disable background scan.
*
+ * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from
+ * userspace. If unset it is assumed the hint comes directly from
+ * a user. If set code could specify exactly what type of source
+ * was used to provide the hint. For the different types of
+ * allowed user regulatory hints see nl80211_user_reg_hint_type.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1493,6 +1502,10 @@
NL80211_ATTR_BG_SCAN_PERIOD,
+ NL80211_ATTR_WDEV,
+
+ NL80211_ATTR_USER_REG_HINT_TYPE,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -1545,6 +1558,8 @@
/* default RSSI threshold for scan results if none specified. */
#define NL80211_SCAN_RSSI_THOLD_OFF -300
+#define NL80211_CQM_TXE_MAX_INTVL 1800
+
/**
* enum nl80211_iftype - (virtual) interface types
*
@@ -1638,12 +1653,20 @@
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
* when getting information about the bitrate of a station.
+ * There are 2 attributes for bitrate, a legacy one that represents
+ * a 16-bit value, and new one that represents a 32-bit value.
+ * If the rate value fits into 16 bit, both attributes are reported
+ * with the same value. If the rate is too high to fit into 16 bits
+ * (>6.5535Gbps) only 32-bit attribute is included.
+ * User space tools encouraged to use the 32-bit attribute and fall
+ * back to the 16-bit one for compatibility with older kernels.
*
* @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
* @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
* @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
* @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
* @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
* @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
@@ -1653,6 +1676,7 @@
NL80211_RATE_INFO_MCS,
NL80211_RATE_INFO_40_MHZ_WIDTH,
NL80211_RATE_INFO_SHORT_GI,
+ NL80211_RATE_INFO_BITRATE32,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -2045,6 +2069,26 @@
};
/**
+ * enum nl80211_user_reg_hint_type - type of user regulatory hint
+ *
+ * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always
+ * assumed if the attribute is not set.
+ * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular
+ * base station. Device drivers that have been tested to work
+ * properly to support this type of hint can enable these hints
+ * by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature
+ * capability on the struct wiphy. The wireless core will
+ * ignore all cell base station hints until at least one device
+ * present has been registered with the wireless core that
+ * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a
+ * supported feature.
+ */
+enum nl80211_user_reg_hint_type {
+ NL80211_USER_REG_HINT_USER = 0,
+ NL80211_USER_REG_HINT_CELL_BASE = 1,
+};
+
+/**
* enum nl80211_survey_info - survey information
*
* These attribute types are used with %NL80211_ATTR_SURVEY_INFO
@@ -2575,6 +2619,17 @@
* @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event
* @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many
* consecutive packets were not acknowledged by the peer
+ * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures
+ * during the given %NL80211_ATTR_CQM_TXE_INTVL before an
+ * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and
+ * %NL80211_ATTR_CQM_TXE_PKTS is generated.
+ * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given
+ * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is
+ * checked.
+ * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic
+ * interval in which %NL80211_ATTR_CQM_TXE_PKTS and
+ * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
+ * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
* @__NL80211_ATTR_CQM_AFTER_LAST: internal
* @NL80211_ATTR_CQM_MAX: highest key attribute
*/
@@ -2584,6 +2639,9 @@
NL80211_ATTR_CQM_RSSI_HYST,
NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
NL80211_ATTR_CQM_PKT_LOSS_EVENT,
+ NL80211_ATTR_CQM_TXE_RATE,
+ NL80211_ATTR_CQM_TXE_PKTS,
+ NL80211_ATTR_CQM_TXE_INTVL,
/* keep last */
__NL80211_ATTR_CQM_AFTER_LAST,
@@ -2933,11 +2991,15 @@
* @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates.
* @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up
* the connected inactive stations in AP mode.
+ * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested
+ * to work properly to suppport receiving regulatory hints from
+ * cellular base stations.
*/
enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
NL80211_FEATURE_HT_IBSS = 1 << 1,
NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2,
+ NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3,
};
/**
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 0d6ef93..7b077cb 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -13,6 +13,41 @@
#include "eap_common.h"
/**
+ * eap_hdr_len_valid - Validate EAP header length field
+ * @msg: EAP frame (starting with EAP header)
+ * @min_payload: Minimum payload length needed
+ * Returns: 1 for valid header, 0 for invalid
+ *
+ * This is a helper function that does minimal validation of EAP messages. The
+ * length field is verified to be large enough to include the header and not
+ * too large to go beyond the end of the buffer.
+ */
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
+{
+ const struct eap_hdr *hdr;
+ size_t len;
+
+ if (msg == NULL)
+ return 0;
+
+ hdr = wpabuf_head(msg);
+
+ if (wpabuf_len(msg) < sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+ return 0;
+ }
+
+ len = be_to_host16(hdr->length);
+ if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
+ wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
* eap_hdr_validate - Validate EAP header
* @vendor: Expected EAP Vendor-Id (0 = IETF)
* @eap_type: Expected EAP type number
@@ -35,19 +70,11 @@
const u8 *pos;
size_t len;
+ if (!eap_hdr_len_valid(msg, 1))
+ return NULL;
+
hdr = wpabuf_head(msg);
-
- if (wpabuf_len(msg) < sizeof(*hdr)) {
- wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
- return NULL;
- }
-
len = be_to_host16(hdr->length);
- if (len < sizeof(*hdr) + 1 || len > wpabuf_len(msg)) {
- wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
- return NULL;
- }
-
pos = (const u8 *) (hdr + 1);
if (*pos == EAP_TYPE_EXPANDED) {
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index 73f2797..8850c1f 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -1,6 +1,6 @@
/*
* EAP common peer/server definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "wpabuf.h"
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
const struct wpabuf *msg, size_t *plen);
struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 360193a..0d247c4 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -71,9 +71,13 @@
enum {
EAP_VENDOR_IETF = 0,
EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
- EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
+ EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */,
+ EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */
};
+#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP
+#define EAP_VENDOR_TYPE_UNAUTH_TLS 1
+
#define EAP_MSK_LEN 64
#define EAP_EMSK_LEN 64
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 8b43be4..2ed74b8 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -20,6 +20,7 @@
#include "common.h"
#include "pcsc_funcs.h"
#include "state_machine.h"
+#include "ext_password.h"
#include "crypto/crypto.h"
#include "crypto/tls.h"
#include "common/wpa_ctrl.h"
@@ -93,6 +94,9 @@
static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
{
+ ext_password_free(sm->ext_pw_buf);
+ sm->ext_pw_buf = NULL;
+
if (sm->m == NULL || sm->eap_method_priv == NULL)
return;
@@ -185,6 +189,12 @@
{
SM_ENTRY(EAP, DISABLED);
sm->num_rounds = 0;
+ /*
+ * RFC 4137 does not describe clearing of idleWhile here, but doing so
+ * allows the timer tick to be stopped more quickly when EAP is not in
+ * use.
+ */
+ eapol_set_int(sm, EAPOL_idleWhile, 0);
}
@@ -346,6 +356,8 @@
}
eapReqData = eapol_get_eapReqData(sm);
+ if (!eap_hdr_len_valid(eapReqData, 1))
+ return;
/*
* Get ignore, methodState, decision, allowNotifications, and
@@ -434,6 +446,8 @@
SM_ENTRY(EAP, IDENTITY);
eapReqData = eapol_get_eapReqData(sm);
+ if (!eap_hdr_len_valid(eapReqData, 1))
+ return;
eap_sm_processIdentity(sm, eapReqData);
wpabuf_free(sm->eapRespData);
sm->eapRespData = NULL;
@@ -450,6 +464,8 @@
SM_ENTRY(EAP, NOTIFICATION);
eapReqData = eapol_get_eapReqData(sm);
+ if (!eap_hdr_len_valid(eapReqData, 1))
+ return;
eap_sm_processNotify(sm, eapReqData);
wpabuf_free(sm->eapRespData);
sm->eapRespData = NULL;
@@ -867,13 +883,17 @@
static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
{
- const struct eap_hdr *hdr = wpabuf_head(req);
- const u8 *pos = (const u8 *) (hdr + 1);
- pos++;
+ const u8 *pos;
+ size_t msg_len;
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
"EAP authentication started");
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
+ &msg_len);
+ if (pos == NULL)
+ return;
+
/*
* RFC 3748 - 5.1: Identity
* Data field may contain a displayable message in UTF-8. If this
@@ -884,7 +904,7 @@
/* TODO: could save displayable message so that it can be shown to the
* user in case of interaction is required */
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
- pos, be_to_host16(hdr->length) - 5);
+ pos, msg_len);
}
@@ -1915,6 +1935,27 @@
}
+static int eap_get_ext_password(struct eap_sm *sm,
+ struct eap_peer_config *config)
+{
+ char *name;
+
+ if (config->password == NULL)
+ return -1;
+
+ name = os_zalloc(config->password_len + 1);
+ if (name == NULL)
+ return -1;
+ os_memcpy(name, config->password, config->password_len);
+
+ ext_password_free(sm->ext_pw_buf);
+ sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
+ os_free(name);
+
+ return sm->ext_pw_buf == NULL ? -1 : 0;
+}
+
+
/**
* eap_get_config_password - Get password from the network configuration
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
@@ -1926,6 +1967,14 @@
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
return NULL;
+
+ if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if (eap_get_ext_password(sm, config) < 0)
+ return NULL;
+ *len = wpabuf_len(sm->ext_pw_buf);
+ return wpabuf_head(sm->ext_pw_buf);
+ }
+
*len = config->password_len;
return config->password;
}
@@ -1945,6 +1994,14 @@
struct eap_peer_config *config = eap_get_config(sm);
if (config == NULL)
return NULL;
+
+ if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ if (eap_get_ext_password(sm, config) < 0)
+ return NULL;
+ *len = wpabuf_len(sm->ext_pw_buf);
+ return wpabuf_head(sm->ext_pw_buf);
+ }
+
*len = config->password_len;
if (hash)
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
@@ -2256,3 +2313,24 @@
return 1;
}
+
+
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
+{
+ ext_password_free(sm->ext_pw_buf);
+ sm->ext_pw_buf = NULL;
+ sm->ext_pw = ext;
+}
+
+
+/**
+ * eap_set_anon_id - Set or add anonymous identity
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+ * @len: Length of anonymous identity in octets
+ */
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
+{
+ if (sm->eapol_cb->set_anon_id)
+ sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
+}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 6e87475..8bccef1 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -1,6 +1,6 @@
/*
* EAP peer state machine functions (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -235,6 +235,14 @@
*/
void (*notify_status)(void *ctx, const char *status,
const char *parameter);
+
+ /**
+ * set_anon_id - Set or add anonymous identity
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+ * @len: Length of anonymous identity in octets
+ */
+ void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
};
/**
@@ -306,6 +314,10 @@
int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
+struct ext_password_data;
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
+
#endif /* IEEE8021X_EAPOL */
#endif /* EAP_H */
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 1cec4d8..59861cb 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -90,6 +90,7 @@
{
struct eap_aka_data *data;
const char *phase1 = eap_get_config_phase1(sm);
+ struct eap_peer_config *config = eap_get_config(sm);
data = os_zalloc(sizeof(*data));
if (data == NULL)
@@ -102,6 +103,15 @@
data->result_ind = phase1 && os_strstr(phase1, "result_ind=1") != NULL;
+ if (config && config->anonymous_identity) {
+ data->pseudonym = os_malloc(config->anonymous_identity_len);
+ if (data->pseudonym) {
+ os_memcpy(data->pseudonym, config->anonymous_identity,
+ config->anonymous_identity_len);
+ data->pseudonym_len = config->anonymous_identity_len;
+ }
+ }
+
return data;
}
@@ -227,13 +237,15 @@
#define CLEAR_REAUTH_ID 0x02
#define CLEAR_EAP_ID 0x04
-static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
+static void eap_aka_clear_identities(struct eap_sm *sm,
+ struct eap_aka_data *data, int id)
{
if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
@@ -288,6 +300,7 @@
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
+ eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
}
if (attr->next_reauth_id) {
@@ -425,6 +438,8 @@
data->num_id_req = 0;
data->num_notification = 0;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Send Client-Error (error code %d)",
+ err);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
EAP_AKA_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
@@ -486,16 +501,16 @@
data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID);
} else if (id_req != NO_ID_REQ) {
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
+ eap_aka_clear_identities(sm, data, CLEAR_PSEUDONYM |
CLEAR_REAUTH_ID);
}
}
if (id_req != NO_ID_REQ)
- eap_aka_clear_identities(data, CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
@@ -898,7 +913,7 @@
* other words, if no new identities are received, full
* authentication will be used on next reauthentication (using
* pseudonym identity or permanent identity). */
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
if (attr->encr_data) {
u8 *decrypted;
@@ -1126,7 +1141,7 @@
data->nonce_s, data->mk,
data->msk, data->emsk);
}
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
eap_aka_learn_ids(sm, data, &eattr);
if (data->result_ind && attr->result_ind)
@@ -1142,7 +1157,8 @@
if (data->counter > EAP_AKA_MAX_FAST_REAUTHS) {
wpa_printf(MSG_DEBUG, "EAP-AKA: Maximum number of "
"fast reauths performed - force fullauth");
- eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data,
+ CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
os_free(decrypted);
return eap_aka_response_reauth(data, id, 0, data->nonce_s);
@@ -1260,7 +1276,7 @@
static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
- eap_aka_clear_identities(data, CLEAR_EAP_ID);
+ eap_aka_clear_identities(sm, data, CLEAR_EAP_ID);
data->prev_id = -1;
wpabuf_free(data->id_msgs);
data->id_msgs = NULL;
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index a6f6f4c..ed90919 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -35,6 +35,9 @@
*
* If not set, the identity field will be used for both unencrypted and
* protected fields.
+ *
+ * This field can also be used with EAP-SIM/AKA/AKA' to store the
+ * pseudonym identity.
*/
u8 *anonymous_identity;
@@ -619,6 +622,7 @@
int fragment_size;
#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
+#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
/**
* flags - Network configuration flags (bitfield)
*
@@ -626,6 +630,8 @@
* for the network parameters.
* bit 0 = password is represented as a 16-byte NtPasswordHash value
* instead of plaintext password
+ * bit 1 = password is stored in external storage; the value in the
+ * password field is the name of that external entry
*/
u32 flags;
};
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 31d9f7c..7ca5288 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -169,7 +169,7 @@
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_NONE;
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_FAST)) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
eap_fast_deinit(sm, data);
return NULL;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 3318b81..dd94317 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -330,6 +330,9 @@
struct wps_context *wps;
int prev_failure;
+
+ struct ext_password_data *ext_pw;
+ struct wpabuf *ext_pw_buf;
};
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eap_peer/eap_md5.c b/src/eap_peer/eap_md5.c
index e348415..d06befa 100644
--- a/src/eap_peer/eap_md5.c
+++ b/src/eap_peer/eap_md5.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
- * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -86,7 +86,13 @@
id = eap_get_id(resp);
rpos = wpabuf_put(resp, CHAP_MD5_LEN);
- chap_md5(id, password, password_len, challenge, challenge_len, rpos);
+ if (chap_md5(id, password, password_len, challenge, challenge_len,
+ rpos)) {
+ wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+ ret->ignore = TRUE;
+ wpabuf_free(resp);
+ return NULL;
+ }
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
return resp;
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index ff9f50d..4994ff1 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -85,6 +85,7 @@
/* EAP peer method registration calls for statically linked in methods */
int eap_peer_md5_register(void);
int eap_peer_tls_register(void);
+int eap_peer_unauth_tls_register(void);
int eap_peer_mschapv2_register(void);
int eap_peer_peap_register(void);
int eap_peer_ttls_register(void);
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index 3b0a116..fb6c282 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -304,7 +304,9 @@
"EAP-MSCHAPV2: Password changed successfully");
data->prev_error = 0;
os_free(config->password);
- if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
+ if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ /* TODO: update external storage */
+ } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
config->password = os_malloc(16);
config->password_len = 16;
if (config->password) {
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 0caa77e..7fff145 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -159,7 +159,7 @@
data->phase2_type.vendor = EAP_VENDOR_IETF;
data->phase2_type.method = EAP_TYPE_NONE;
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
eap_peap_deinit(sm, data);
return NULL;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index fb4ae82..c936a44 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-SIM (RFC 4186)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -117,6 +117,15 @@
NULL;
}
+ if (config && config->anonymous_identity) {
+ data->pseudonym = os_malloc(config->anonymous_identity_len);
+ if (data->pseudonym) {
+ os_memcpy(data->pseudonym, config->anonymous_identity,
+ config->anonymous_identity_len);
+ data->pseudonym_len = config->anonymous_identity_len;
+ }
+ }
+
eap_sim_state(data, CONTINUE);
return data;
@@ -258,13 +267,15 @@
#define CLEAR_REAUTH_ID 0x02
#define CLEAR_EAP_ID 0x04
-static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
+static void eap_sim_clear_identities(struct eap_sm *sm,
+ struct eap_sim_data *data, int id)
{
if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
+ eap_set_anon_id(sm, NULL, 0);
}
if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
@@ -319,6 +330,7 @@
realm, realm_len);
}
data->pseudonym_len = attr->next_pseudonym_len + realm_len;
+ eap_set_anon_id(sm, data->pseudonym, data->pseudonym_len);
}
if (attr->next_reauth_id) {
@@ -352,6 +364,8 @@
data->num_id_req = 0;
data->num_notification = 0;
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Send Client-Error (error code %d)",
+ err);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_CLIENT_ERROR);
eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
@@ -376,16 +390,16 @@
data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID);
} else if (id_req != NO_ID_REQ) {
identity = eap_get_config_identity(sm, &identity_len);
if (identity) {
- eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
+ eap_sim_clear_identities(sm, data, CLEAR_PSEUDONYM |
CLEAR_REAUTH_ID);
}
}
if (id_req != NO_ID_REQ)
- eap_sim_clear_identities(data, CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
@@ -432,7 +446,8 @@
static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data,
- u8 id, int counter_too_small)
+ u8 id, int counter_too_small,
+ const u8 *nonce_s)
{
struct eap_sim_msg *msg;
unsigned int counter;
@@ -467,7 +482,7 @@
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, data->k_aut, data->nonce_s,
+ return eap_sim_msg_finish(msg, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
@@ -667,7 +682,7 @@
* other words, if no new reauth identity is received, full
* authentication will be used on next reauthentication (using
* pseudonym identity or permanent identity). */
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
if (attr->encr_data) {
u8 *decrypted;
@@ -863,7 +878,7 @@
data->reauth_id = NULL;
data->reauth_id_len = 0;
os_free(decrypted);
- return eap_sim_response_reauth(data, id, 1);
+ return eap_sim_response_reauth(data, id, 1, eattr.nonce_s);
}
data->counter = eattr.counter;
@@ -875,7 +890,7 @@
data->reauth_id, data->reauth_id_len,
data->nonce_s, data->mk, data->msk,
data->emsk);
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
eap_sim_learn_ids(sm, data, &eattr);
if (data->result_ind && attr->result_ind)
@@ -891,10 +906,11 @@
if (data->counter > EAP_SIM_MAX_FAST_REAUTHS) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Maximum number of "
"fast reauths performed - force fullauth");
- eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data,
+ CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
os_free(decrypted);
- return eap_sim_response_reauth(data, id, 0);
+ return eap_sim_response_reauth(data, id, 0, data->nonce_s);
}
@@ -1002,7 +1018,7 @@
static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
- eap_sim_clear_identities(data, CLEAR_EAP_ID);
+ eap_sim_clear_identities(sm, data, CLEAR_EAP_ID);
data->use_result_ind = 0;
}
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index ed52fb6..061a72b 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -22,6 +22,7 @@
struct eap_ssl_data ssl;
u8 *key_data;
void *ssl_ctx;
+ u8 eap_type;
};
@@ -44,7 +45,7 @@
data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
sm->ssl_ctx;
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
if (config->engine) {
@@ -62,10 +63,39 @@
return NULL;
}
+ data->eap_type = EAP_TYPE_TLS;
+
return data;
}
+#ifdef EAP_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+ sm->ssl_ctx;
+
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
+ EAP_UNAUTH_TLS_TYPE)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_deinit(sm, data);
+ return NULL;
+ }
+
+ data->eap_type = EAP_UNAUTH_TLS_TYPE;
+
+ return data;
+}
+#endif /* EAP_UNAUTH_TLS */
+
+
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
@@ -109,7 +139,7 @@
return resp;
}
- return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
+ return eap_peer_tls_build_ack(id, data->eap_type, 0);
}
@@ -149,7 +179,7 @@
const u8 *pos;
struct eap_tls_data *data = priv;
- pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
+ pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
reqData, &left, &flags);
if (pos == NULL)
return NULL;
@@ -162,8 +192,8 @@
}
resp = NULL;
- res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TLS, 0, id,
- pos, left, &resp);
+ res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
+ id, pos, left, &resp);
if (res < 0) {
return eap_tls_failure(sm, data, ret, res, resp, id);
@@ -174,7 +204,7 @@
if (res == 1) {
wpabuf_free(resp);
- return eap_peer_tls_build_ack(id, EAP_TYPE_TLS, 0);
+ return eap_peer_tls_build_ack(id, data->eap_type, 0);
}
return resp;
@@ -285,3 +315,34 @@
eap_peer_method_free(eap);
return ret;
}
+
+
+#ifdef EAP_UNAUTH_TLS
+int eap_peer_unauth_tls_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_unauth_tls_init;
+ eap->deinit = eap_tls_deinit;
+ eap->process = eap_tls_process;
+ eap->isKeyAvailable = eap_tls_isKeyAvailable;
+ eap->getKey = eap_tls_getKey;
+ eap->get_status = eap_tls_get_status;
+ eap->has_reauth_data = eap_tls_has_reauth_data;
+ eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+ eap->init_for_reauth = eap_tls_init_for_reauth;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
+#endif /* EAP_UNAUTH_TLS */
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 69e83d9..7eefe8c 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -16,6 +16,18 @@
#include "eap_config.h"
+static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier)
+{
+ if (type == EAP_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
+ code, identifier);
+ return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+ identifier);
+}
+
+
static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
const u8 **data, size_t *data_len)
{
@@ -48,6 +60,10 @@
params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
if (os_strstr(txt, "tls_disable_time_checks=1"))
params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
+ if (os_strstr(txt, "tls_disable_session_ticket=1"))
+ params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+ if (os_strstr(txt, "tls_disable_session_ticket=0"))
+ params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
}
@@ -99,6 +115,18 @@
struct eap_peer_config *config, int phase2)
{
os_memset(params, 0, sizeof(*params));
+ if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
+ /*
+ * Some deployed authentication servers seem to be unable to
+ * handle the TLS Session Ticket extension (they are supposed
+ * to ignore unrecognized TLS extensions, but end up rejecting
+ * the ClientHello instead). As a workaround, disable use of
+ * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
+ * EAP-TTLS (EAP-FAST uses session ticket, so any server that
+ * supports EAP-FAST does not need this workaround).
+ */
+ params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+ }
if (phase2) {
wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
eap_tls_params_from_conf2(params, config);
@@ -182,13 +210,14 @@
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
* @data: Data for TLS processing
* @config: Pointer to the network configuration
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
* Returns: 0 on success, -1 on failure
*
* This function is used to initialize shared TLS functionality for EAP-TLS,
* EAP-PEAP, EAP-TTLS, and EAP-FAST.
*/
int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- struct eap_peer_config *config)
+ struct eap_peer_config *config, u8 eap_type)
{
struct tls_connection_params params;
@@ -196,6 +225,7 @@
return -1;
data->eap = sm;
+ data->eap_type = eap_type;
data->phase2 = sm->init_phase2;
data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
sm->ssl_ctx;
@@ -259,7 +289,9 @@
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len)
{
+#ifndef CONFIG_FIPS
struct tls_keys keys;
+#endif /* CONFIG_FIPS */
u8 *rnd = NULL, *out;
out = os_malloc(len);
@@ -271,6 +303,7 @@
== 0)
return out;
+#ifndef CONFIG_FIPS
/*
* TLS library did not support key generation, so get the needed TLS
* session parameters and use an internal implementation of TLS PRF to
@@ -299,6 +332,7 @@
return out;
fail:
+#endif /* CONFIG_FIPS */
os_free(out);
os_free(rnd);
return NULL;
@@ -516,9 +550,8 @@
length_included = 1;
}
- *out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
- 1 + length_included * 4 + len,
- EAP_CODE_RESPONSE, id);
+ *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
+ EAP_CODE_RESPONSE, id);
if (*out_data == NULL)
return -1;
@@ -656,8 +689,7 @@
{
struct wpabuf *resp;
- resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE,
- id);
+ resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
if (resp == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
@@ -750,7 +782,13 @@
return NULL;
}
- pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left);
+ if (eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
+ &left);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
+ &left);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
@@ -946,8 +984,8 @@
"method '%s'", start);
} else {
num_methods++;
- _methods = os_realloc(methods,
- num_methods * sizeof(*methods));
+ _methods = os_realloc_array(methods, num_methods,
+ sizeof(*methods));
if (_methods == NULL) {
os_free(methods);
os_free(buf);
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index 771385b..91d3a25 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -68,6 +68,11 @@
* ssl_ctx - TLS library context to use for the connection
*/
void *ssl_ctx;
+
+ /**
+ * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ */
+ u8 eap_type;
};
@@ -80,9 +85,12 @@
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- struct eap_peer_config *config);
+ struct eap_peer_config *config, u8 eap_type);
void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
const char *label, size_t len);
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e09f5e5..9360a42 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -110,7 +110,7 @@
data->phase2_eap_type.method = EAP_TYPE_NONE;
}
- if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
eap_ttls_deinit(sm, data);
return NULL;
@@ -401,6 +401,7 @@
struct eap_method_ret *ret,
struct wpabuf **resp)
{
+#ifdef EAP_MSCHAPv2
struct wpabuf *msg;
u8 *buf, *pos, *challenge, *peer_challenge;
const u8 *identity, *password;
@@ -488,6 +489,10 @@
}
return 0;
+#else /* EAP_MSCHAPv2 */
+ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+ return -1;
+#endif /* EAP_MSCHAPv2 */
}
@@ -1042,6 +1047,7 @@
struct eap_method_ret *ret,
struct ttls_parse_avp *parse)
{
+#ifdef EAP_MSCHAPv2
if (parse->mschapv2_error) {
wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
"MS-CHAP-Error - failed");
@@ -1090,6 +1096,10 @@
* with EAP-Success after this.
*/
return 1;
+#else /* EAP_MSCHAPv2 */
+ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+ return -1;
+#endif /* EAP_MSCHAPv2 */
}
diff --git a/src/eap_peer/eap_vendor_test.c b/src/eap_peer/eap_vendor_test.c
index f23b9d2..040d1e7 100644
--- a/src/eap_peer/eap_vendor_test.c
+++ b/src/eap_peer/eap_vendor_test.c
@@ -19,7 +19,7 @@
#endif /* TEST_PENDING_REQUEST */
-#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
#define EAP_VENDOR_TYPE 0xfcfbfaf9
diff --git a/src/eap_peer/mschapv2.c b/src/eap_peer/mschapv2.c
index 67dbadb..37e6735 100644
--- a/src/eap_peer/mschapv2.c
+++ b/src/eap_peer/mschapv2.c
@@ -63,22 +63,28 @@
if (pwhash) {
wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
password, password_len);
- generate_nt_response_pwhash(auth_challenge, peer_challenge,
- username, username_len,
- password, nt_response);
- generate_authenticator_response_pwhash(
- password, peer_challenge, auth_challenge,
- username, username_len, nt_response, auth_response);
+ if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
+ username, username_len,
+ password, nt_response) ||
+ generate_authenticator_response_pwhash(
+ password, peer_challenge, auth_challenge,
+ username, username_len, nt_response,
+ auth_response))
+ return -1;
} else {
wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
password, password_len);
- generate_nt_response(auth_challenge, peer_challenge,
- username, username_len,
- password, password_len, nt_response);
- generate_authenticator_response(password, password_len,
- peer_challenge, auth_challenge,
- username, username_len,
- nt_response, auth_response);
+ if (generate_nt_response(auth_challenge, peer_challenge,
+ username, username_len,
+ password, password_len,
+ nt_response) ||
+ generate_authenticator_response(password, password_len,
+ peer_challenge,
+ auth_challenge,
+ username, username_len,
+ nt_response,
+ auth_response))
+ return -1;
}
wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
nt_response, MSCHAPV2_NT_RESPONSE_LEN);
@@ -94,7 +100,8 @@
hash_nt_password_hash(password_hash, password_hash_hash))
return -1;
}
- get_master_key(password_hash_hash, nt_response, master_key);
+ if (get_master_key(password_hash_hash, nt_response, master_key))
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
master_key, MSCHAPV2_MASTER_KEY_LEN);
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index dfb0ff5..f92704a 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -151,7 +151,7 @@
int user_eap_method_index;
int init_phase2;
void *ssl_ctx;
- void *eap_sim_db_priv;
+ struct eap_sim_db_data *eap_sim_db_priv;
Boolean backend_auth;
Boolean update_user;
int eap_server;
diff --git a/src/eap_server/eap_methods.h b/src/eap_server/eap_methods.h
index 9667cf4..bc810a9 100644
--- a/src/eap_server/eap_methods.h
+++ b/src/eap_server/eap_methods.h
@@ -26,6 +26,7 @@
int eap_server_identity_register(void);
int eap_server_md5_register(void);
int eap_server_tls_register(void);
+int eap_server_unauth_tls_register(void);
int eap_server_mschapv2_register(void);
int eap_server_peap_register(void);
int eap_server_tlv_register(void);
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 44c089f..15f7e22 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -275,6 +275,11 @@
{
SM_ENTRY(EAP, INTEGRITY_CHECK);
+ if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
+ sm->ignore = TRUE;
+ return;
+ }
+
if (sm->m->check) {
sm->ignore = sm->m->check(sm, sm->eap_method_priv,
sm->eap_if.eapRespData);
@@ -309,6 +314,9 @@
{
SM_ENTRY(EAP, METHOD_RESPONSE);
+ if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
+ return;
+
sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
if (sm->m->isDone(sm, sm->eap_method_priv)) {
eap_sm_Policy_update(sm, NULL, 0);
@@ -380,6 +388,9 @@
}
sm->m = NULL;
+ if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
+ return;
+
nak = wpabuf_head(sm->eap_if.eapRespData);
if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
len = be_to_host16(nak->length);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 9cd5509..a965cac 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -49,12 +49,12 @@
u8 *network_name;
size_t network_name_len;
u16 kdf;
+ int identity_round;
+ char permanent[20]; /* Permanent username */
};
-static void eap_aka_determine_identity(struct eap_sm *sm,
- struct eap_aka_data *data,
- int before_identity, int after_reauth);
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data);
static const char * eap_aka_state_txt(int state)
@@ -87,6 +87,96 @@
}
+static int eap_aka_check_identity_reauth(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ const char *username)
+{
+ if (data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX)
+ return 0;
+ if (data->eap_method == EAP_TYPE_AKA &&
+ username[0] != EAP_AKA_REAUTH_ID_PREFIX)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth username '%s'", username);
+ data->reauth = eap_sim_db_get_reauth_entry(sm->eap_sim_db_priv,
+ username);
+ if (data->reauth == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown reauth identity - "
+ "request full auth identity");
+ /* Remain in IDENTITY state for another round */
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast re-authentication");
+ os_strlcpy(data->permanent, data->reauth->permanent,
+ sizeof(data->permanent));
+ data->counter = data->reauth->counter;
+ if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+ os_memcpy(data->k_encr, data->reauth->k_encr,
+ EAP_SIM_K_ENCR_LEN);
+ os_memcpy(data->k_aut, data->reauth->k_aut,
+ EAP_AKA_PRIME_K_AUT_LEN);
+ os_memcpy(data->k_re, data->reauth->k_re,
+ EAP_AKA_PRIME_K_RE_LEN);
+ } else {
+ os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
+ }
+
+ eap_aka_state(data, REAUTH);
+ return 1;
+}
+
+
+static void eap_aka_check_identity(struct eap_sm *sm,
+ struct eap_aka_data *data)
+{
+ char *username;
+
+ /* Check if we already know the identity from EAP-Response/Identity */
+
+ username = sim_get_username(sm->identity, sm->identity_len);
+ if (username == NULL)
+ return;
+
+ if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+ os_free(username);
+ /*
+ * Since re-auth username was recognized, skip AKA/Identity
+ * exchange.
+ */
+ return;
+ }
+
+ if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
+ const char *permanent;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
+ username);
+ permanent = eap_sim_db_get_permanent(
+ sm->eap_sim_db_priv, username);
+ if (permanent == NULL) {
+ os_free(username);
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
+ "identity - request permanent identity");
+ /* Remain in IDENTITY state for another round */
+ return;
+ }
+ os_strlcpy(data->permanent, permanent,
+ sizeof(data->permanent));
+ /*
+ * Since pseudonym username was recognized, skip AKA/Identity
+ * exchange.
+ */
+ eap_aka_fullauth(sm, data);
+ }
+
+ os_free(username);
+}
+
+
static void * eap_aka_init(struct eap_sm *sm)
{
struct eap_aka_data *data;
@@ -103,8 +193,8 @@
data->eap_method = EAP_TYPE_AKA;
data->state = IDENTITY;
- eap_aka_determine_identity(sm, data, 1, 0);
data->pending_id = -1;
+ eap_aka_check_identity(sm, data);
return data;
}
@@ -136,8 +226,8 @@
data->network_name_len = os_strlen(network_name);
data->state = IDENTITY;
- eap_aka_determine_identity(sm, data, 1, 0);
data->pending_id = -1;
+ eap_aka_check_identity(sm, data);
return data;
}
@@ -264,21 +354,8 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
EAP_AKA_SUBTYPE_IDENTITY);
- if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len)) {
- if (sm->identity_len > 0 &&
- (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
- sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
- /* Reauth id may have expired - try fullauth */
- wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
- NULL, 0);
- } else {
- wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
- NULL, 0);
- }
- } else {
+ data->identity_round++;
+ if (data->identity_round == 1) {
/*
* RFC 4187, Chap. 4.1.4 recommends that identity from EAP is
* ignored and the AKA/Identity is used to request the
@@ -286,6 +363,18 @@
*/
wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
+ } else if (data->identity_round > 3) {
+ /* Cannot use more than three rounds of Identity messages */
+ return NULL;
+ } else if (sm->identity && sm->identity_len > 0 &&
+ (sm->identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
+ sm->identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX)) {
+ /* Reauth id may have expired - try fullauth */
+ wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
buf = eap_sim_msg_finish(msg, NULL, NULL, 0);
if (eap_aka_add_id_msg(data, buf) < 0) {
@@ -622,93 +711,72 @@
static void eap_aka_determine_identity(struct eap_sm *sm,
- struct eap_aka_data *data,
- int before_identity, int after_reauth)
+ struct eap_aka_data *data)
{
- const u8 *identity;
- size_t identity_len;
- int res;
-
- identity = NULL;
- identity_len = 0;
-
- if (after_reauth && data->reauth) {
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- } else if (sm->identity && sm->identity_len > 0 &&
- (sm->identity[0] == EAP_AKA_PERMANENT_PREFIX ||
- sm->identity[0] == EAP_AKA_PRIME_PERMANENT_PREFIX)) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- } else {
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
- sm->identity,
- sm->identity_len,
- &identity_len);
- if (identity == NULL) {
- data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, sm->identity,
- sm->identity_len);
- if (data->reauth &&
- data->reauth->aka_prime !=
- (data->eap_method == EAP_TYPE_AKA_PRIME)) {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
- "was for different AKA version");
- data->reauth = NULL;
- }
- if (data->reauth) {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
- "re-authentication");
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- data->counter = data->reauth->counter;
- if (data->eap_method == EAP_TYPE_AKA_PRIME) {
- os_memcpy(data->k_encr,
- data->reauth->k_encr,
- EAP_SIM_K_ENCR_LEN);
- os_memcpy(data->k_aut,
- data->reauth->k_aut,
- EAP_AKA_PRIME_K_AUT_LEN);
- os_memcpy(data->k_re,
- data->reauth->k_re,
- EAP_AKA_PRIME_K_RE_LEN);
- } else {
- os_memcpy(data->mk, data->reauth->mk,
- EAP_SIM_MK_LEN);
- }
- }
- }
- }
-
- if (identity == NULL ||
- eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len) < 0) {
- if (before_identity) {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
- "not known - send AKA-Identity request");
- eap_aka_state(data, IDENTITY);
- return;
- } else {
- wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
- "permanent user name is known; try to use "
- "it");
- /* eap_sim_db_get_aka_auth() will report failure, if
- * this identity is not known. */
- }
- }
+ char *username;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
- identity, identity_len);
+ sm->identity, sm->identity_len);
- if (!after_reauth && data->reauth) {
- eap_aka_state(data, REAUTH);
+ username = sim_get_username(sm->identity, sm->identity_len);
+ if (username == NULL) {
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
return;
}
- res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
- identity_len, data->rand, data->autn,
- data->ik, data->ck, data->res,
- &data->res_len, sm);
+ if (eap_aka_check_identity_reauth(sm, data, username) > 0) {
+ os_free(username);
+ return;
+ }
+
+ if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_PSEUDONYM_PREFIX)) {
+ const char *permanent;
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Pseudonym username '%s'",
+ username);
+ permanent = eap_sim_db_get_permanent(
+ sm->eap_sim_db_priv, username);
+ os_free(username);
+ if (permanent == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown pseudonym "
+ "identity - request permanent identity");
+ /* Remain in IDENTITY state for another round */
+ return;
+ }
+ os_strlcpy(data->permanent, permanent,
+ sizeof(data->permanent));
+ } else if ((data->eap_method == EAP_TYPE_AKA_PRIME &&
+ username[0] == EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+ (data->eap_method == EAP_TYPE_AKA &&
+ username[0] == EAP_AKA_PERMANENT_PREFIX)) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent username '%s'",
+ username);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized username '%s'",
+ username);
+ os_free(username);
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ eap_aka_fullauth(sm, data);
+}
+
+
+static void eap_aka_fullauth(struct eap_sm *sm, struct eap_aka_data *data)
+{
+ size_t identity_len;
+ int res;
+
+ res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, data->permanent,
+ data->rand, data->autn, data->ik,
+ data->ck, data->res, &data->res_len, sm);
if (res == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
"not yet available - pending request");
@@ -772,6 +840,8 @@
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
+ u8 *new_identity;
+
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
if (attr->mac || attr->iv || attr->encr_data) {
@@ -782,17 +852,30 @@
return;
}
- if (attr->identity) {
- os_free(sm->identity);
- sm->identity = os_malloc(attr->identity_len);
- if (sm->identity) {
- os_memcpy(sm->identity, attr->identity,
- attr->identity_len);
- sm->identity_len = attr->identity_len;
- }
+ /*
+ * We always request identity with AKA/Identity, so the peer is
+ * required to have replied with one.
+ */
+ if (!attr->identity || attr->identity_len == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Peer did not provide any "
+ "identity");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
}
- eap_aka_determine_identity(sm, data, 0, 0);
+ new_identity = os_malloc(attr->identity_len);
+ if (new_identity == NULL) {
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+ os_free(sm->identity);
+ sm->identity = new_identity;
+ os_memcpy(sm->identity, attr->identity, attr->identity_len);
+ sm->identity_len = attr->identity_len;
+
+ eap_aka_determine_identity(sm, data);
if (eap_get_id(respData) == data->pending_id) {
data->pending_id = -1;
eap_aka_add_id_msg(data, respData);
@@ -817,9 +900,6 @@
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
- const u8 *identity;
- size_t identity_len;
-
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
#ifdef EAP_SERVER_AKA_PRIME
@@ -892,16 +972,8 @@
} else
eap_aka_state(data, SUCCESS);
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len, &identity_len);
- if (identity == NULL) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
@@ -909,16 +981,15 @@
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
- identity,
- identity_len,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->k_encr, data->k_aut,
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->mk);
@@ -947,9 +1018,8 @@
* maintaining a local flag stating whether this AUTS has already been
* reported. */
if (!data->auts_reported &&
- eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len, attr->auts,
- data->rand)) {
+ eap_sim_db_resynchronize(sm->eap_sim_db_priv, data->permanent,
+ attr->auts, data->rand)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
eap_aka_state(data, NOTIFICATION);
@@ -957,8 +1027,7 @@
}
data->auts_reported = 1;
- /* Try again after resynchronization */
- eap_aka_determine_identity(sm, data, 0, 0);
+ /* Remain in CHALLENGE state to re-try after resynchronization */
}
@@ -969,8 +1038,6 @@
{
struct eap_sim_attrs eattr;
u8 *decrypted = NULL;
- const u8 *identity, *id2;
- size_t identity_len, id2_len;
wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
@@ -1013,7 +1080,7 @@
wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
"included AT_COUNTER_TOO_SMALL - starting full "
"authentication");
- eap_aka_determine_identity(sm, data, 0, 1);
+ eap_aka_fullauth(sm, data);
return;
}
@@ -1024,35 +1091,19 @@
} else
eap_aka_state(data, SUCCESS);
- if (data->reauth) {
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- } else {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
- id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
- identity_len, &id2_len);
- if (id2) {
- identity = id2;
- identity_len = id2_len;
- }
-
if (data->next_reauth_id) {
if (data->eap_method == EAP_TYPE_AKA_PRIME) {
#ifdef EAP_SERVER_AKA_PRIME
eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
- identity,
- identity_len,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->k_encr, data->k_aut,
data->k_re);
#endif /* EAP_SERVER_AKA_PRIME */
} else {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv,
+ data->permanent,
data->next_reauth_id,
data->counter + 1,
data->mk);
diff --git a/src/eap_server/eap_server_md5.c b/src/eap_server/eap_server_md5.c
index f4bb261..5a5e290 100644
--- a/src/eap_server/eap_server_md5.c
+++ b/src/eap_server/eap_server_md5.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-MD5 server
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -119,8 +119,12 @@
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, CHAP_MD5_LEN);
id = eap_get_id(respData);
- chap_md5(id, sm->user->password, sm->user->password_len,
- data->challenge, CHALLENGE_LEN, hash);
+ if (chap_md5(id, sm->user->password, sm->user->password_len,
+ data->challenge, CHALLENGE_LEN, hash)) {
+ wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+ data->state = FAILURE;
+ return;
+ }
if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) {
wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success");
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 6658d9c..f83c3cb 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-SIM (RFC 4186)
- * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -36,6 +36,8 @@
struct eap_sim_reauth *reauth;
u16 notification;
int use_result_ind;
+ int start_round;
+ char permanent[20]; /* Permanent username */
};
@@ -105,26 +107,32 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_START);
- if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len)) {
- if (sm->identity_len > 0 &&
- sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
- /* Reauth id may have expired - try fullauth */
- wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0,
- NULL, 0);
- } else {
- wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
- eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0,
- NULL, 0);
- }
- } else {
+ data->start_round++;
+ if (data->start_round == 1) {
/*
* RFC 4186, Chap. 4.2.4 recommends that identity from EAP is
* ignored and the SIM/Start is used to request the identity.
*/
wpa_printf(MSG_DEBUG, " AT_ANY_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_ANY_ID_REQ, 0, NULL, 0);
+ } else if (data->start_round > 3) {
+ /* Cannot use more than three rounds of Start messages */
+ return NULL;
+ } else if (data->start_round == 0) {
+ /*
+ * This is a special case that is used to recover from
+ * AT_COUNTER_TOO_SMALL during re-authentication. Since we
+ * already know the identity of the peer, there is no need to
+ * request any identity in this case.
+ */
+ } else if (sm->identity && sm->identity_len > 0 &&
+ sm->identity[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+ /* Reauth id may have expired - try fullauth */
+ wpa_printf(MSG_DEBUG, " AT_FULLAUTH_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_FULLAUTH_ID_REQ, 0, NULL, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
wpa_printf(MSG_DEBUG, " AT_VERSION_LIST");
ver[0] = 0;
@@ -337,18 +345,22 @@
static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
- struct eap_sim_data *data = priv;
const u8 *pos;
size_t len;
- u8 subtype;
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM, respData, &len);
if (pos == NULL || len < 3) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
return TRUE;
}
- subtype = *pos;
+ return FALSE;
+}
+
+
+static Boolean eap_sim_unexpected_subtype(struct eap_sim_data *data,
+ u8 subtype)
+{
if (subtype == EAP_SIM_SUBTYPE_CLIENT_ERROR)
return FALSE;
@@ -402,85 +414,113 @@
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
- const u8 *identity;
size_t identity_len;
u8 ver_list[2];
+ u8 *new_identity;
+ char *username;
wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
- if (attr->identity) {
- os_free(sm->identity);
- sm->identity = os_malloc(attr->identity_len);
- if (sm->identity) {
- os_memcpy(sm->identity, attr->identity,
- attr->identity_len);
- sm->identity_len = attr->identity_len;
- }
+ if (data->start_round == 0) {
+ /*
+ * Special case for AT_COUNTER_TOO_SMALL recovery - no identity
+ * was requested since we already know it.
+ */
+ goto skip_id_update;
}
- identity = NULL;
- identity_len = 0;
-
- if (sm->identity && sm->identity_len > 0 &&
- sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- } else {
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
- sm->identity,
- sm->identity_len,
- &identity_len);
- if (identity == NULL) {
- data->reauth = eap_sim_db_get_reauth_entry(
- sm->eap_sim_db_priv, sm->identity,
- sm->identity_len);
- if (data->reauth) {
- wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
- "re-authentication");
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- data->counter = data->reauth->counter;
- os_memcpy(data->mk, data->reauth->mk,
- EAP_SIM_MK_LEN);
- }
- }
+ /*
+ * We always request identity in SIM/Start, so the peer is required to
+ * have replied with one.
+ */
+ if (!attr->identity || attr->identity_len == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Peer did not provide any "
+ "identity");
+ goto failed;
}
- if (identity == NULL) {
- wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
- " user name");
- eap_sim_state(data, FAILURE);
- return;
- }
+ new_identity = os_malloc(attr->identity_len);
+ if (new_identity == NULL)
+ goto failed;
+ os_free(sm->identity);
+ sm->identity = new_identity;
+ os_memcpy(sm->identity, attr->identity, attr->identity_len);
+ sm->identity_len = attr->identity_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
- identity, identity_len);
+ sm->identity, sm->identity_len);
+ username = sim_get_username(sm->identity, sm->identity_len);
+ if (username == NULL)
+ goto failed;
- if (data->reauth) {
+ if (username[0] == EAP_SIM_REAUTH_ID_PREFIX) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Reauth username '%s'",
+ username);
+ data->reauth = eap_sim_db_get_reauth_entry(
+ sm->eap_sim_db_priv, username);
+ os_free(username);
+ if (data->reauth == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown reauth "
+ "identity - request full auth identity");
+ /* Remain in START state for another round */
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast re-authentication");
+ os_strlcpy(data->permanent, data->reauth->permanent,
+ sizeof(data->permanent));
+ data->counter = data->reauth->counter;
+ os_memcpy(data->mk, data->reauth->mk, EAP_SIM_MK_LEN);
eap_sim_state(data, REAUTH);
return;
}
+ if (username[0] == EAP_SIM_PSEUDONYM_PREFIX) {
+ const char *permanent;
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Pseudonym username '%s'",
+ username);
+ permanent = eap_sim_db_get_permanent(
+ sm->eap_sim_db_priv, username);
+ os_free(username);
+ if (permanent == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown pseudonym "
+ "identity - request permanent identity");
+ /* Remain in START state for another round */
+ return;
+ }
+ os_strlcpy(data->permanent, permanent,
+ sizeof(data->permanent));
+ } else if (username[0] == EAP_SIM_PERMANENT_PREFIX) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Permanent username '%s'",
+ username);
+ os_strlcpy(data->permanent, username, sizeof(data->permanent));
+ os_free(username);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized username '%s'",
+ username);
+ os_free(username);
+ goto failed;
+ }
+
+skip_id_update:
+ /* Full authentication */
+
if (attr->nonce_mt == NULL || attr->selected_version < 0) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Start/Response missing "
"required attributes");
- eap_sim_state(data, FAILURE);
- return;
+ goto failed;
}
if (!eap_sim_supported_ver(data, attr->selected_version)) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Peer selected unsupported "
"version %d", attr->selected_version);
- eap_sim_state(data, FAILURE);
- return;
+ goto failed;
}
data->counter = 0; /* reset re-auth counter since this is full auth */
data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, identity, identity_len,
- EAP_SIM_MAX_CHAL,
+ sm->eap_sim_db_priv, data->permanent, EAP_SIM_MAX_CHAL,
(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
if (data->num_chal == EAP_SIM_DB_PENDING) {
wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
@@ -491,8 +531,7 @@
if (data->num_chal < 2) {
wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
"authentication triplets for the peer");
- eap_sim_state(data, FAILURE);
- return;
+ goto failed;
}
identity_len = sm->identity_len;
@@ -513,6 +552,11 @@
data->emsk);
eap_sim_state(data, CHALLENGE);
+ return;
+
+failed:
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
}
@@ -521,16 +565,14 @@
struct wpabuf *respData,
struct eap_sim_attrs *attr)
{
- const u8 *identity;
- size_t identity_len;
-
if (attr->mac == NULL ||
eap_sim_verify_mac(data->k_aut, respData, attr->mac,
(u8 *) data->sres,
data->num_chal * EAP_SIM_SRES_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
"did not include valid AT_MAC");
- eap_sim_state(data, FAILURE);
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
return;
}
@@ -543,22 +585,13 @@
} else
eap_sim_state(data, SUCCESS);
- identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
- sm->identity_len, &identity_len);
- if (identity == NULL) {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
if (data->next_pseudonym) {
- eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, data->permanent,
data->next_pseudonym);
data->next_pseudonym = NULL;
}
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
data->next_reauth_id, data->counter + 1,
data->mk);
data->next_reauth_id = NULL;
@@ -573,8 +606,6 @@
{
struct eap_sim_attrs eattr;
u8 *decrypted = NULL;
- const u8 *identity, *id2;
- size_t identity_len, id2_len;
if (attr->mac == NULL ||
eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
@@ -610,6 +641,16 @@
wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
"the correct AT_MAC");
+
+ if (eattr.counter_too_small) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
+ "included AT_COUNTER_TOO_SMALL - starting full "
+ "authentication");
+ data->start_round = -1;
+ eap_sim_state(data, START);
+ return;
+ }
+
if (sm->eap_sim_aka_result_ind && attr->result_ind) {
data->use_result_ind = 1;
data->notification = EAP_SIM_SUCCESS;
@@ -617,24 +658,9 @@
} else
eap_sim_state(data, SUCCESS);
- if (data->reauth) {
- identity = data->reauth->identity;
- identity_len = data->reauth->identity_len;
- } else {
- identity = sm->identity;
- identity_len = sm->identity_len;
- }
-
- id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
- identity_len, &id2_len);
- if (id2) {
- identity = id2;
- identity_len = id2_len;
- }
-
if (data->next_reauth_id) {
- eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
- identity_len, data->next_reauth_id,
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, data->permanent,
+ data->next_reauth_id,
data->counter + 1, data->mk);
data->next_reauth_id = NULL;
} else {
@@ -645,7 +671,8 @@
return;
fail:
- eap_sim_state(data, FAILURE);
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
data->reauth = NULL;
os_free(decrypted);
@@ -696,8 +723,24 @@
subtype = *pos;
pos += 3;
+ if (eap_sim_unexpected_subtype(data, subtype)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Unrecognized or unexpected "
+ "EAP-SIM Subtype in EAP Response");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
+ return;
+ }
+
if (eap_sim_parse_attr(pos, end, &attr, 0, 0)) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to parse attributes");
+ if (subtype != EAP_SIM_SUBTYPE_CLIENT_ERROR &&
+ (data->state == START || data->state == CHALLENGE ||
+ data->state == REAUTH)) {
+ data->notification =
+ EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_sim_state(data, NOTIFICATION);
+ return;
+ }
eap_sim_state(data, FAILURE);
return;
}
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index d34ef41..447f47c 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -21,6 +21,7 @@
struct eap_ssl_data ssl;
enum { START, CONTINUE, SUCCESS, FAILURE } state;
int established;
+ u8 eap_type;
};
@@ -65,10 +66,34 @@
return NULL;
}
+ data->eap_type = EAP_TYPE_TLS;
+
return data;
}
+#ifdef EAP_SERVER_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+ struct eap_tls_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = START;
+
+ if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+ eap_tls_reset(sm, data);
+ return NULL;
+ }
+
+ data->eap_type = EAP_UNAUTH_TLS_TYPE;
+ return data;
+}
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
+
static void eap_tls_reset(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
@@ -84,8 +109,7 @@
{
struct wpabuf *req;
- req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST,
- id);
+ req = eap_tls_msg_alloc(data->eap_type, 1, EAP_CODE_REQUEST, id);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
"request");
@@ -107,11 +131,11 @@
struct wpabuf *res;
if (data->ssl.state == FRAG_ACK) {
- return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
+ return eap_server_tls_build_ack(id, data->eap_type, 0);
}
if (data->ssl.state == WAIT_FRAG_ACK) {
- res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
+ res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0,
id);
goto check_established;
}
@@ -129,7 +153,7 @@
return NULL;
}
- res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
+ res = eap_server_tls_build_msg(&data->ssl, data->eap_type, 0, id);
check_established:
if (data->established && data->ssl.state != WAIT_FRAG_ACK) {
@@ -146,10 +170,17 @@
static Boolean eap_tls_check(struct eap_sm *sm, void *priv,
struct wpabuf *respData)
{
+ struct eap_tls_data *data = priv;
const u8 *pos;
size_t len;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len);
+ if (data->eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+ &len);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_type,
+ respData, &len);
if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
return TRUE;
@@ -178,7 +209,7 @@
{
struct eap_tls_data *data = priv;
if (eap_server_tls_process(sm, &data->ssl, respData, data,
- EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
+ data->eap_type, NULL, eap_tls_process_msg) <
0)
eap_tls_state(data, FAILURE);
}
@@ -278,3 +309,34 @@
eap_server_method_free(eap);
return ret;
}
+
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+int eap_server_unauth_tls_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS,
+ "UNAUTH-TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_unauth_tls_init;
+ eap->reset = eap_tls_reset;
+ eap->buildReq = eap_tls_buildReq;
+ eap->check = eap_tls_check;
+ eap->process = eap_tls_process;
+ eap->isDone = eap_tls_isDone;
+ eap->getKey = eap_tls_getKey;
+ eap->isSuccess = eap_tls_isSuccess;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
+#endif /* EAP_SERVER_UNAUTH_TLS */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 88a410d..31be2ec 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -18,6 +18,18 @@
static void eap_server_tls_free_in_buf(struct eap_ssl_data *data);
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier)
+{
+ if (type == EAP_UNAUTH_TLS_TYPE)
+ return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
+ code, identifier);
+ return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+ identifier);
+}
+
+
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer)
{
@@ -131,8 +143,7 @@
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
plen += 4;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
- EAP_CODE_REQUEST, id);
+ req = eap_tls_msg_alloc(eap_type, plen, EAP_CODE_REQUEST, id);
if (req == NULL)
return NULL;
@@ -168,8 +179,7 @@
{
struct wpabuf *req;
- req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
- id);
+ req = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_REQUEST, id);
if (req == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "SSL: Building ACK");
@@ -359,7 +369,13 @@
size_t left;
int ret, res = 0;
- pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
+ if (eap_type == EAP_UNAUTH_TLS_TYPE)
+ pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+ EAP_VENDOR_TYPE_UNAUTH_TLS, respData,
+ &left);
+ else
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData,
+ &left);
if (pos == NULL || left < 1)
return 0; /* Should not happen - frame already validated */
flags = *pos++;
diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c
index 3d2403e..67a3dfa 100644
--- a/src/eap_server/eap_server_tnc.c
+++ b/src/eap_server/eap_server_tnc.c
@@ -9,7 +9,6 @@
#include "includes.h"
#include "common.h"
-#include "base64.h"
#include "eap_i.h"
#include "tncs.h"
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 45fbf52..647bd2f 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -674,6 +674,13 @@
return;
}
+ if (sm->identity == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: No user identity "
+ "known");
+ eap_ttls_state(data, FAILURE);
+ return;
+ }
+
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
@@ -979,11 +986,12 @@
if (parse.user_name) {
os_free(sm->identity);
sm->identity = os_malloc(parse.user_name_len);
- if (sm->identity) {
- os_memcpy(sm->identity, parse.user_name,
- parse.user_name_len);
- sm->identity_len = parse.user_name_len;
+ if (sm->identity == NULL) {
+ eap_ttls_state(data, FAILURE);
+ goto done;
}
+ os_memcpy(sm->identity, parse.user_name, parse.user_name_len);
+ sm->identity_len = parse.user_name_len;
if (eap_user_get(sm, parse.user_name, parse.user_name_len, 1)
!= 0) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 Identity not "
diff --git a/src/eap_server/eap_server_vendor_test.c b/src/eap_server/eap_server_vendor_test.c
index e4c8bc3..30f600d 100644
--- a/src/eap_server/eap_server_vendor_test.c
+++ b/src/eap_server/eap_server_vendor_test.c
@@ -12,7 +12,7 @@
#include "eap_i.h"
-#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_ID EAP_VENDOR_HOSTAP
#define EAP_VENDOR_TYPE 0xfcfbfaf9
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index ce3238c..257013e 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -17,6 +17,9 @@
#include "includes.h"
#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
#include "common.h"
#include "crypto/random.h"
@@ -26,15 +29,13 @@
struct eap_sim_pseudonym {
struct eap_sim_pseudonym *next;
- u8 *identity;
- size_t identity_len;
- char *pseudonym;
+ char *permanent; /* permanent username */
+ char *pseudonym; /* pseudonym username */
};
struct eap_sim_db_pending {
struct eap_sim_db_pending *next;
- u8 imsi[20];
- size_t imsi_len;
+ char imsi[20];
enum { PENDING, SUCCESS, FAILURE } state;
void *cb_session_ctx;
struct os_time timestamp;
@@ -66,19 +67,316 @@
struct eap_sim_pseudonym *pseudonyms;
struct eap_sim_reauth *reauths;
struct eap_sim_db_pending *pending;
+#ifdef CONFIG_SQLITE
+ sqlite3 *sqlite_db;
+ char db_tmp_identity[100];
+ char db_tmp_pseudonym_str[100];
+ struct eap_sim_pseudonym db_tmp_pseudonym;
+ struct eap_sim_reauth db_tmp_reauth;
+#endif /* CONFIG_SQLITE */
};
+#ifdef CONFIG_SQLITE
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+ char cmd[128];
+ os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+ return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_pseudonym(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE pseudonyms("
+ " permanent CHAR(21) PRIMARY KEY,"
+ " pseudonym CHAR(21) NOT NULL"
+ ");";
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
+ "pseudonym information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int db_table_create_reauth(sqlite3 *db)
+{
+ char *err = NULL;
+ const char *sql =
+ "CREATE TABLE reauth("
+ " permanent CHAR(21) PRIMARY KEY,"
+ " reauth_id CHAR(21) NOT NULL,"
+ " counter INTEGER,"
+ " mk CHAR(40),"
+ " k_encr CHAR(32),"
+ " k_aut CHAR(64),"
+ " k_re CHAR(64)"
+ ");";
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Adding database table for "
+ "reauth information");
+ if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+ sqlite3 *db;
+
+ if (sqlite3_open(db_file, &db)) {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: Failed to open database "
+ "%s: %s", db_file, sqlite3_errmsg(db));
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "pseudonyms") &&
+ db_table_create_pseudonym(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ if (!db_table_exists(db, "reauth") &&
+ db_table_create_reauth(db) < 0) {
+ sqlite3_close(db);
+ return NULL;
+ }
+
+ return db;
+}
+
+
+static int valid_db_string(const char *str)
+{
+ const char *pos = str;
+ while (*pos) {
+ if ((*pos < '0' || *pos > '9') &&
+ (*pos < 'a' || *pos > 'f'))
+ return 0;
+ pos++;
+ }
+ return 1;
+}
+
+
+static int db_add_pseudonym(struct eap_sim_db_data *data,
+ const char *permanent, char *pseudonym)
+{
+ char cmd[128];
+ char *err = NULL;
+
+ if (!valid_db_string(permanent) || !valid_db_string(pseudonym)) {
+ os_free(pseudonym);
+ return -1;
+ }
+
+ os_snprintf(cmd, sizeof(cmd), "INSERT OR REPLACE INTO pseudonyms "
+ "(permanent, pseudonym) VALUES ('%s', '%s');",
+ permanent, pseudonym);
+ os_free(pseudonym);
+ if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
+ {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int get_pseudonym_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct eap_sim_db_data *data = ctx;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
+ os_strlcpy(data->db_tmp_identity, argv[i],
+ sizeof(data->db_tmp_identity));
+ }
+ }
+
+ return 0;
+}
+
+
+static char *
+db_get_pseudonym(struct eap_sim_db_data *data, const char *pseudonym)
+{
+ char cmd[128];
+
+ if (!valid_db_string(pseudonym))
+ return NULL;
+ os_memset(&data->db_tmp_identity, 0, sizeof(data->db_tmp_identity));
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT permanent FROM pseudonyms WHERE pseudonym='%s';",
+ pseudonym);
+ if (sqlite3_exec(data->sqlite_db, cmd, get_pseudonym_cb, data, NULL) !=
+ SQLITE_OK)
+ return NULL;
+ if (data->db_tmp_identity[0] == '\0')
+ return NULL;
+ return data->db_tmp_identity;
+}
+
+
+static int db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+ char *reauth_id, u16 counter, const u8 *mk,
+ const u8 *k_encr, const u8 *k_aut, const u8 *k_re)
+{
+ char cmd[2000], *pos, *end;
+ char *err = NULL;
+
+ if (!valid_db_string(permanent) || !valid_db_string(reauth_id)) {
+ os_free(reauth_id);
+ return -1;
+ }
+
+ pos = cmd;
+ end = pos + sizeof(cmd);
+ pos += os_snprintf(pos, end - pos, "INSERT OR REPLACE INTO reauth "
+ "(permanent, reauth_id, counter%s%s%s%s) "
+ "VALUES ('%s', '%s', %u",
+ mk ? ", mk" : "",
+ k_encr ? ", k_encr" : "",
+ k_aut ? ", k_aut" : "",
+ k_re ? ", k_re" : "",
+ permanent, reauth_id, counter);
+ os_free(reauth_id);
+
+ if (mk) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, mk, EAP_SIM_MK_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ if (k_encr) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, k_encr,
+ EAP_SIM_K_ENCR_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ if (k_aut) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, k_aut,
+ EAP_AKA_PRIME_K_AUT_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ if (k_re) {
+ pos += os_snprintf(pos, end - pos, ", '");
+ pos += wpa_snprintf_hex(pos, end - pos, k_re,
+ EAP_AKA_PRIME_K_RE_LEN);
+ pos += os_snprintf(pos, end - pos, "'");
+ }
+
+ os_snprintf(pos, end - pos, ");");
+
+ if (sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, &err) != SQLITE_OK)
+ {
+ wpa_printf(MSG_ERROR, "EAP-SIM DB: SQLite error: %s", err);
+ sqlite3_free(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int get_reauth_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+ struct eap_sim_db_data *data = ctx;
+ int i;
+ struct eap_sim_reauth *reauth = &data->db_tmp_reauth;
+
+ for (i = 0; i < argc; i++) {
+ if (os_strcmp(col[i], "permanent") == 0 && argv[i]) {
+ os_strlcpy(data->db_tmp_identity, argv[i],
+ sizeof(data->db_tmp_identity));
+ reauth->permanent = data->db_tmp_identity;
+ } else if (os_strcmp(col[i], "counter") == 0 && argv[i]) {
+ reauth->counter = atoi(argv[i]);
+ } else if (os_strcmp(col[i], "mk") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->mk, sizeof(reauth->mk));
+ } else if (os_strcmp(col[i], "k_encr") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->k_encr,
+ sizeof(reauth->k_encr));
+ } else if (os_strcmp(col[i], "k_aut") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->k_aut,
+ sizeof(reauth->k_aut));
+ } else if (os_strcmp(col[i], "k_re") == 0 && argv[i]) {
+ hexstr2bin(argv[i], reauth->k_re,
+ sizeof(reauth->k_re));
+ }
+ }
+
+ return 0;
+}
+
+
+static struct eap_sim_reauth *
+db_get_reauth(struct eap_sim_db_data *data, const char *reauth_id)
+{
+ char cmd[256];
+
+ if (!valid_db_string(reauth_id))
+ return NULL;
+ os_memset(&data->db_tmp_reauth, 0, sizeof(data->db_tmp_reauth));
+ os_strlcpy(data->db_tmp_pseudonym_str, reauth_id,
+ sizeof(data->db_tmp_pseudonym_str));
+ data->db_tmp_reauth.reauth_id = data->db_tmp_pseudonym_str;
+ os_snprintf(cmd, sizeof(cmd),
+ "SELECT * FROM reauth WHERE reauth_id='%s';", reauth_id);
+ if (sqlite3_exec(data->sqlite_db, cmd, get_reauth_cb, data, NULL) !=
+ SQLITE_OK)
+ return NULL;
+ if (data->db_tmp_reauth.permanent == NULL)
+ return NULL;
+ return &data->db_tmp_reauth;
+}
+
+
+static void db_remove_reauth(struct eap_sim_db_data *data,
+ struct eap_sim_reauth *reauth)
+{
+ char cmd[256];
+
+ if (!valid_db_string(reauth->permanent))
+ return;
+ os_snprintf(cmd, sizeof(cmd),
+ "DELETE FROM reauth WHERE permanent='%s';",
+ reauth->permanent);
+ sqlite3_exec(data->sqlite_db, cmd, NULL, NULL, NULL);
+}
+
+#endif /* CONFIG_SQLITE */
+
+
static struct eap_sim_db_pending *
-eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
- size_t imsi_len, int aka)
+eap_sim_db_get_pending(struct eap_sim_db_data *data, const char *imsi, int aka)
{
struct eap_sim_db_pending *entry, *prev = NULL;
entry = data->pending;
while (entry) {
- if (entry->aka == aka && entry->imsi_len == imsi_len &&
- os_memcmp(entry->imsi, imsi, imsi_len) == 0) {
+ if (entry->aka == aka && os_strcmp(entry->imsi, imsi) == 0) {
if (prev)
prev->next = entry->next;
else
@@ -113,7 +411,7 @@
* (IMSI = ASCII string, Kc/SRES/RAND = hex string)
*/
- entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 0);
+ entry = eap_sim_db_get_pending(data, imsi, 0);
if (entry == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
"received message found");
@@ -191,7 +489,7 @@
* (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
*/
- entry = eap_sim_db_get_pending(data, (u8 *) imsi, os_strlen(imsi), 1);
+ entry = eap_sim_db_get_pending(data, imsi, 1);
if (entry == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
"received message found");
@@ -340,6 +638,7 @@
addr.sun_family = AF_UNIX;
os_snprintf(addr.sun_path, sizeof(addr.sun_path),
"/tmp/eap_sim_db_%d-%d", getpid(), counter++);
+ os_free(data->local_sock);
data->local_sock = os_strdup(addr.sun_path);
if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("bind(eap_sim_db)");
@@ -389,11 +688,13 @@
* @ctx: Context pointer for get_complete_cb
* Returns: Pointer to a private data structure or %NULL on failure
*/
-void * eap_sim_db_init(const char *config,
- void (*get_complete_cb)(void *ctx, void *session_ctx),
- void *ctx)
+struct eap_sim_db_data *
+eap_sim_db_init(const char *config,
+ void (*get_complete_cb)(void *ctx, void *session_ctx),
+ void *ctx)
{
struct eap_sim_db_data *data;
+ char *pos;
data = os_zalloc(sizeof(*data));
if (data == NULL)
@@ -405,10 +706,23 @@
data->fname = os_strdup(config);
if (data->fname == NULL)
goto fail;
+ pos = os_strstr(data->fname, " db=");
+ if (pos) {
+ *pos = '\0';
+#ifdef CONFIG_SQLITE
+ pos += 4;
+ data->sqlite_db = db_open(pos);
+ if (data->sqlite_db == NULL)
+ goto fail;
+#endif /* CONFIG_SQLITE */
+ }
if (os_strncmp(data->fname, "unix:", 5) == 0) {
- if (eap_sim_db_open_socket(data))
- goto fail;
+ if (eap_sim_db_open_socket(data)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External database "
+ "connection not available - will retry "
+ "later");
+ }
}
return data;
@@ -423,7 +737,7 @@
static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
{
- os_free(p->identity);
+ os_free(p->permanent);
os_free(p->pseudonym);
os_free(p);
}
@@ -431,7 +745,7 @@
static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
{
- os_free(r->identity);
+ os_free(r->permanent);
os_free(r->reauth_id);
os_free(r);
}
@@ -448,6 +762,13 @@
struct eap_sim_reauth *r, *prevr;
struct eap_sim_db_pending *pending, *prev_pending;
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db) {
+ sqlite3_close(data->sqlite_db);
+ data->sqlite_db = NULL;
+ }
+#endif /* CONFIG_SQLITE */
+
eap_sim_db_close_socket(data);
os_free(data->fname);
@@ -514,9 +835,8 @@
/**
* eap_sim_db_get_gsm_triplets - Get GSM triplets
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username (prefix | IMSI)
* @max_chal: Maximum number of triplets
* @_rand: Buffer for RAND values
* @kc: Buffer for Kc values
@@ -528,9 +848,6 @@
* callback function registered with eap_sim_db_init() will be called once the
* results become available.
*
- * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
- * ASCII format.
- *
* When using an external server for GSM triplets, this function can always
* start a request and return EAP_SIM_DB_PENDING immediately if authentication
* triplets are not available. Once the triplets are received, callback
@@ -539,39 +856,28 @@
* function will then be called again and the newly received triplets will then
* be given to the caller.
*/
-int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
- size_t identity_len, int max_chal,
+int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
+ const char *username, int max_chal,
u8 *_rand, u8 *kc, u8 *sres,
void *cb_session_ctx)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_db_pending *entry;
int len, ret;
- size_t i;
char msg[40];
+ const char *imsi;
+ size_t imsi_len;
- if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
+ if (username == NULL || username[0] != EAP_SIM_PERMANENT_PREFIX ||
+ username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+ username);
return EAP_SIM_DB_FAILURE;
}
- identity++;
- identity_len--;
- for (i = 0; i < identity_len; i++) {
- if (identity[i] == '@') {
- identity_len = i;
- break;
- }
- }
- if (identity_len + 1 > sizeof(entry->imsi)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
- return EAP_SIM_DB_FAILURE;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
- identity, identity_len);
+ imsi = username + 1;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI '%s'",
+ imsi);
- entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
+ entry = eap_sim_db_get_pending(data, imsi, 0);
if (entry) {
int num_chal;
if (entry->state == FAILURE) {
@@ -606,18 +912,19 @@
return EAP_SIM_DB_FAILURE;
}
+ imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
- if (len < 0 || len + identity_len >= sizeof(msg))
+ if (len < 0 || len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
- os_memcpy(msg + len, identity, identity_len);
- len += identity_len;
+ os_memcpy(msg + len, imsi, imsi_len);
+ len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
return EAP_SIM_DB_FAILURE;
len += ret;
- wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
- "data for IMSI", identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
+ "data for IMSI '%s'", imsi);
if (eap_sim_db_send(data, msg, len) < 0)
return EAP_SIM_DB_FAILURE;
@@ -626,8 +933,7 @@
return EAP_SIM_DB_FAILURE;
os_get_time(&entry->timestamp);
- os_memcpy(entry->imsi, identity, identity_len);
- entry->imsi_len = identity_len;
+ os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
eap_sim_db_add_pending(data, entry);
@@ -637,196 +943,6 @@
}
-static struct eap_sim_pseudonym *
-eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- char *pseudonym;
- size_t len;
- struct eap_sim_pseudonym *p;
-
- if (identity_len == 0 ||
- (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
- identity[0] != EAP_AKA_PSEUDONYM_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PSEUDONYM_PREFIX))
- return NULL;
-
- /* Remove possible realm from identity */
- len = 0;
- while (len < identity_len) {
- if (identity[len] == '@')
- break;
- len++;
- }
-
- pseudonym = os_malloc(len + 1);
- if (pseudonym == NULL)
- return NULL;
- os_memcpy(pseudonym, identity, len);
- pseudonym[len] = '\0';
-
- p = data->pseudonyms;
- while (p) {
- if (os_strcmp(p->pseudonym, pseudonym) == 0)
- break;
- p = p->next;
- }
-
- os_free(pseudonym);
-
- return p;
-}
-
-
-static struct eap_sim_pseudonym *
-eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- struct eap_sim_pseudonym *p;
-
- if (identity_len == 0 ||
- (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX))
- return NULL;
-
- p = data->pseudonyms;
- while (p) {
- if (identity_len == p->identity_len &&
- os_memcmp(p->identity, identity, identity_len) == 0)
- break;
- p = p->next;
- }
-
- return p;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- char *reauth_id;
- size_t len;
- struct eap_sim_reauth *r;
-
- if (identity_len == 0 ||
- (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
- identity[0] != EAP_AKA_REAUTH_ID_PREFIX &&
- identity[0] != EAP_AKA_PRIME_REAUTH_ID_PREFIX))
- return NULL;
-
- /* Remove possible realm from identity */
- len = 0;
- while (len < identity_len) {
- if (identity[len] == '@')
- break;
- len++;
- }
-
- reauth_id = os_malloc(len + 1);
- if (reauth_id == NULL)
- return NULL;
- os_memcpy(reauth_id, identity, len);
- reauth_id[len] = '\0';
-
- r = data->reauths;
- while (r) {
- if (os_strcmp(r->reauth_id, reauth_id) == 0)
- break;
- r = r->next;
- }
-
- os_free(reauth_id);
-
- return r;
-}
-
-
-static struct eap_sim_reauth *
-eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len)
-{
- struct eap_sim_pseudonym *p;
- struct eap_sim_reauth *r;
-
- if (identity_len == 0)
- return NULL;
-
- p = eap_sim_db_get_pseudonym(data, identity, identity_len);
- if (p == NULL)
- p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
- if (p) {
- identity = p->identity;
- identity_len = p->identity_len;
- }
-
- r = data->reauths;
- while (r) {
- if (identity_len == r->identity_len &&
- os_memcmp(r->identity, identity, identity_len) == 0)
- break;
- r = r->next;
- }
-
- return r;
-}
-
-
-/**
- * eap_sim_db_identity_known - Verify whether the given identity is known
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
- * Returns: 0 if the user is found or -1 on failure
- *
- * In most cases, the user name is ['0','1','6'] | IMSI, i.e., 1 followed by
- * the IMSI in ASCII format for EAP-SIM, ['2','3','7'] | pseudonym, or
- * ['4','5','7'] | reauth_id.
- */
-int eap_sim_db_identity_known(void *priv, const u8 *identity,
- size_t identity_len)
-{
- struct eap_sim_db_data *data = priv;
-
- if (identity == NULL || identity_len < 2)
- return -1;
-
- if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
- identity[0] == EAP_AKA_PSEUDONYM_PREFIX ||
- identity[0] == EAP_AKA_PRIME_PSEUDONYM_PREFIX) {
- struct eap_sim_pseudonym *p =
- eap_sim_db_get_pseudonym(data, identity, identity_len);
- return p ? 0 : -1;
- }
-
- if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
- identity[0] == EAP_AKA_REAUTH_ID_PREFIX ||
- identity[0] == EAP_AKA_PRIME_REAUTH_ID_PREFIX) {
- struct eap_sim_reauth *r =
- eap_sim_db_get_reauth(data, identity, identity_len);
- return r ? 0 : -1;
- }
-
- if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) {
- /* Unknown identity prefix */
- return -1;
- }
-
- /* TODO: Should consider asking HLR/AuC gateway whether this permanent
- * identity is known. If it is, EAP-SIM/AKA can skip identity request.
- * In case of EAP-AKA, this would reduce number of needed round-trips.
- * Ideally, this would be done with one wait, i.e., just request
- * authentication data and store it for the next use. This would then
- * need to use similar pending-request functionality as the normal
- * request for authentication data at later phase.
- */
- return -1;
-}
-
-
static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
{
char *id, *pos, *end;
@@ -849,7 +965,7 @@
/**
* eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
- * @priv: Private data pointer from eap_sim_db_init()
+ * @data: Private data pointer from eap_sim_db_init()
* @method: EAP method (SIM/AKA/AKA')
* Returns: Next pseudonym (allocated string) or %NULL on failure
*
@@ -858,9 +974,9 @@
* with eap_sim_db_add_pseudonym() once the authentication has been completed
* successfully. Caller is responsible for freeing the returned buffer.
*/
-char * eap_sim_db_get_next_pseudonym(void *priv, enum eap_sim_db_method method)
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
+ enum eap_sim_db_method method)
{
- struct eap_sim_db_data *data = priv;
char prefix = EAP_SIM_REAUTH_ID_PREFIX;
switch (method) {
@@ -881,7 +997,7 @@
/**
* eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
- * @priv: Private data pointer from eap_sim_db_init()
+ * @data: Private data pointer from eap_sim_db_init()
* @method: EAP method (SIM/AKA/AKA')
* Returns: Next reauth_id (allocated string) or %NULL on failure
*
@@ -891,9 +1007,9 @@
* has been completed successfully. Caller is responsible for freeing the
* returned buffer.
*/
-char * eap_sim_db_get_next_reauth_id(void *priv, enum eap_sim_db_method method)
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
+ enum eap_sim_db_method method)
{
- struct eap_sim_db_data *data = priv;
char prefix = EAP_SIM_REAUTH_ID_PREFIX;
switch (method) {
@@ -914,9 +1030,8 @@
/**
* eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
* @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
* e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
* free it.
@@ -925,20 +1040,22 @@
* This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
* responsible of freeing pseudonym buffer once it is not needed anymore.
*/
-int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
- size_t identity_len, char *pseudonym)
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+ const char *permanent, char *pseudonym)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_pseudonym *p;
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
- identity, identity_len);
- wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add pseudonym '%s' for permanent "
+ "username '%s'", pseudonym, permanent);
/* TODO: could store last two pseudonyms */
- p = eap_sim_db_get_pseudonym(data, identity, identity_len);
- if (p == NULL)
- p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
-
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_add_pseudonym(data, permanent, pseudonym);
+#endif /* CONFIG_SQLITE */
+ for (p = data->pseudonyms; p; p = p->next) {
+ if (os_strcmp(permanent, p->permanent) == 0)
+ break;
+ }
if (p) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
"pseudonym: %s", p->pseudonym);
@@ -954,14 +1071,12 @@
}
p->next = data->pseudonyms;
- p->identity = os_malloc(identity_len);
- if (p->identity == NULL) {
+ p->permanent = os_strdup(permanent);
+ if (p->permanent == NULL) {
os_free(p);
os_free(pseudonym);
return -1;
}
- os_memcpy(p->identity, identity, identity_len);
- p->identity_len = identity_len;
p->pseudonym = pseudonym;
data->pseudonyms = p;
@@ -971,18 +1086,16 @@
static struct eap_sim_reauth *
-eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
- size_t identity_len, char *reauth_id, u16 counter)
+eap_sim_db_add_reauth_data(struct eap_sim_db_data *data,
+ const char *permanent,
+ char *reauth_id, u16 counter)
{
struct eap_sim_reauth *r;
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
- identity, identity_len);
- wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
-
- r = eap_sim_db_get_reauth(data, identity, identity_len);
- if (r == NULL)
- r = eap_sim_db_get_reauth_id(data, identity, identity_len);
+ for (r = data->reauths; r; r = r->next) {
+ if (os_strcmp(r->permanent, permanent) == 0)
+ break;
+ }
if (r) {
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
@@ -997,14 +1110,12 @@
}
r->next = data->reauths;
- r->identity = os_malloc(identity_len);
- if (r->identity == NULL) {
+ r->permanent = os_strdup(permanent);
+ if (r->permanent == NULL) {
os_free(r);
os_free(reauth_id);
return NULL;
}
- os_memcpy(r->identity, identity, identity_len);
- r->identity_len = identity_len;
r->reauth_id = reauth_id;
data->reauths = r;
wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
@@ -1019,7 +1130,7 @@
/**
* eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
* @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
+ * @permanent: Permanent username
* @identity_len: Length of identity
* @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
* e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
@@ -1032,20 +1143,24 @@
* EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
* anymore.
*/
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id, u16 counter,
- const u8 *mk)
+int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+ char *reauth_id, u16 counter, const u8 *mk)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r;
- r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
- counter);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
+ "identity '%s'", reauth_id, permanent);
+
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_add_reauth(data, permanent, reauth_id, counter, mk,
+ NULL, NULL, NULL);
+#endif /* CONFIG_SQLITE */
+ r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
if (r == NULL)
return -1;
os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
- r->aka_prime = 0;
return 0;
}
@@ -1054,9 +1169,8 @@
#ifdef EAP_SERVER_AKA_PRIME
/**
* eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @permanent: Permanent username
* @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
* e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
* free it.
@@ -1070,20 +1184,25 @@
* EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
* anymore.
*/
-int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id,
- u16 counter, const u8 *k_encr, const u8 *k_aut,
- const u8 *k_re)
+int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
+ const char *permanent, char *reauth_id,
+ u16 counter, const u8 *k_encr,
+ const u8 *k_aut, const u8 *k_re)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r;
- r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
- counter);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Add reauth_id '%s' for permanent "
+ "identity '%s'", reauth_id, permanent);
+
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_add_reauth(data, permanent, reauth_id, counter, NULL,
+ k_encr, k_aut, k_re);
+#endif /* CONFIG_SQLITE */
+ r = eap_sim_db_add_reauth_data(data, permanent, reauth_id, counter);
if (r == NULL)
return -1;
- r->aka_prime = 1;
os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
@@ -1095,66 +1214,75 @@
/**
* eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @len: Buffer for length of the returned permanent identity
- * Returns: Pointer to the permanent identity, or %NULL if not found
+ * @data: Private data pointer from eap_sim_db_init()
+ * @pseudonym: Pseudonym username
+ * Returns: Pointer to permanent username or %NULL if not found
*/
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
- size_t identity_len, size_t *len)
+const char *
+eap_sim_db_get_permanent(struct eap_sim_db_data *data, const char *pseudonym)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_pseudonym *p;
- if (identity == NULL)
- return NULL;
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_get_pseudonym(data, pseudonym);
+#endif /* CONFIG_SQLITE */
- p = eap_sim_db_get_pseudonym(data, identity, identity_len);
- if (p == NULL)
- p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
- if (p == NULL)
- return NULL;
+ p = data->pseudonyms;
+ while (p) {
+ if (os_strcmp(p->pseudonym, pseudonym) == 0)
+ return p->permanent;
+ p = p->next;
+ }
- *len = p->identity_len;
- return p->identity;
+ return NULL;
}
/**
* eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity, pseudonym, or
- * reauth_id)
- * @identity_len: Length of identity
+ * @data: Private data pointer from eap_sim_db_init()
+ * @reauth_id: Fast re-authentication username
* Returns: Pointer to the re-auth entry, or %NULL if not found
*/
struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
- size_t identity_len)
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+ const char *reauth_id)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r;
- if (identity == NULL)
- return NULL;
- r = eap_sim_db_get_reauth(data, identity, identity_len);
- if (r == NULL)
- r = eap_sim_db_get_reauth_id(data, identity, identity_len);
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db)
+ return db_get_reauth(data, reauth_id);
+#endif /* CONFIG_SQLITE */
+
+ r = data->reauths;
+ while (r) {
+ if (os_strcmp(r->reauth_id, reauth_id) == 0)
+ break;
+ r = r->next;
+ }
+
return r;
}
/**
* eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
+ * @data: Private data pointer from eap_sim_db_init()
* @reauth: Pointer to re-authentication entry from
* eap_sim_db_get_reauth_entry()
*/
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+ struct eap_sim_reauth *reauth)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_reauth *r, *prev = NULL;
+#ifdef CONFIG_SQLITE
+ if (data->sqlite_db) {
+ db_remove_reauth(data, reauth);
+ return;
+ }
+#endif /* CONFIG_SQLITE */
r = data->reauths;
while (r) {
if (r == reauth) {
@@ -1173,9 +1301,8 @@
/**
* eap_sim_db_get_aka_auth - Get AKA authentication values
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username (prefix | IMSI)
* @_rand: Buffer for RAND value
* @autn: Buffer for AUTN value
* @ik: Buffer for IK value
@@ -1188,9 +1315,6 @@
* case, the callback function registered with eap_sim_db_init() will be
* called once the results become available.
*
- * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
- * ASCII format for EAP-AKA and '6' | IMSI for EAP-AKA'.
- *
* When using an external server for AKA authentication, this function can
* always start a request and return EAP_SIM_DB_PENDING immediately if
* authentication triplets are not available. Once the authentication data are
@@ -1199,41 +1323,29 @@
* eap_sim_db_get_aka_auth() function will then be called again and the newly
* received triplets will then be given to the caller.
*/
-int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
- size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
- u8 *ck, u8 *res, size_t *res_len,
- void *cb_session_ctx)
+int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
+ u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
+ u8 *res, size_t *res_len, void *cb_session_ctx)
{
- struct eap_sim_db_data *data = priv;
struct eap_sim_db_pending *entry;
int len;
- size_t i;
char msg[40];
+ const char *imsi;
+ size_t imsi_len;
- if (identity_len < 2 || identity == NULL ||
- (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
+ if (username == NULL ||
+ (username[0] != EAP_AKA_PERMANENT_PREFIX &&
+ username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+ username[1] == '\0' || os_strlen(username) > sizeof(entry->imsi)) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+ username);
return EAP_SIM_DB_FAILURE;
}
- identity++;
- identity_len--;
- for (i = 0; i < identity_len; i++) {
- if (identity[i] == '@') {
- identity_len = i;
- break;
- }
- }
- if (identity_len + 1 > sizeof(entry->imsi)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
- return EAP_SIM_DB_FAILURE;
- }
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
- identity, identity_len);
+ imsi = username + 1;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+ imsi);
- entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
+ entry = eap_sim_db_get_pending(data, imsi, 1);
if (entry) {
if (entry->state == FAILURE) {
os_free(entry);
@@ -1264,14 +1376,15 @@
return EAP_SIM_DB_FAILURE;
}
+ imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
- if (len < 0 || len + identity_len >= sizeof(msg))
+ if (len < 0 || len + imsi_len >= sizeof(msg))
return EAP_SIM_DB_FAILURE;
- os_memcpy(msg + len, identity, identity_len);
- len += identity_len;
+ os_memcpy(msg + len, imsi, imsi_len);
+ len += imsi_len;
- wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
- "data for IMSI", identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
+ "data for IMSI '%s'", imsi);
if (eap_sim_db_send(data, msg, len) < 0)
return EAP_SIM_DB_FAILURE;
@@ -1281,8 +1394,7 @@
os_get_time(&entry->timestamp);
entry->aka = 1;
- os_memcpy(entry->imsi, identity, identity_len);
- entry->imsi_len = identity_len;
+ os_strlcpy(entry->imsi, imsi, sizeof(entry->imsi));
entry->cb_session_ctx = cb_session_ctx;
entry->state = PENDING;
eap_sim_db_add_pending(data, entry);
@@ -1294,9 +1406,8 @@
/**
* eap_sim_db_resynchronize - Resynchronize AKA AUTN
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: User name identity
- * @identity_len: Length of identity in bytes
+ * @data: Private data pointer from eap_sim_db_init()
+ * @username: Permanent username
* @auts: AUTS value from the peer
* @_rand: RAND value used in the rejected message
* Returns: 0 on success, -1 on failure
@@ -1307,43 +1418,35 @@
* eap_sim_db_get_aka_auth() will be called again to to fetch updated
* RAND/AUTN values for the next challenge.
*/
-int eap_sim_db_resynchronize(void *priv, const u8 *identity,
- size_t identity_len, const u8 *auts,
- const u8 *_rand)
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+ const char *username,
+ const u8 *auts, const u8 *_rand)
{
- struct eap_sim_db_data *data = priv;
- size_t i;
+ const char *imsi;
+ size_t imsi_len;
- if (identity_len < 2 || identity == NULL ||
- (identity[0] != EAP_AKA_PERMANENT_PREFIX &&
- identity[0] != EAP_AKA_PRIME_PERMANENT_PREFIX)) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
+ if (username == NULL ||
+ (username[0] != EAP_AKA_PERMANENT_PREFIX &&
+ username[0] != EAP_AKA_PRIME_PERMANENT_PREFIX) ||
+ username[1] == '\0' || os_strlen(username) > 20) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: unexpected username '%s'",
+ username);
return -1;
}
- identity++;
- identity_len--;
- for (i = 0; i < identity_len; i++) {
- if (identity[i] == '@') {
- identity_len = i;
- break;
- }
- }
- if (identity_len > 20) {
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
- identity, identity_len);
- return -1;
- }
+ imsi = username + 1;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI '%s'",
+ imsi);
if (data->sock >= 0) {
char msg[100];
int len, ret;
+ imsi_len = os_strlen(imsi);
len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
- if (len < 0 || len + identity_len >= sizeof(msg))
+ if (len < 0 || len + imsi_len >= sizeof(msg))
return -1;
- os_memcpy(msg + len, identity, identity_len);
- len += identity_len;
+ os_memcpy(msg + len, imsi, imsi_len);
+ len += imsi_len;
ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
@@ -1357,11 +1460,42 @@
len += ret;
len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
_rand, EAP_AKA_RAND_LEN);
- wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
- "IMSI", identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
+ "IMSI '%s'", imsi);
if (eap_sim_db_send(data, msg, len) < 0)
return -1;
}
return 0;
}
+
+
+/**
+ * sim_get_username - Extract username from SIM identity
+ * @identity: Identity
+ * @identity_len: Identity length
+ * Returns: Allocated buffer with the username part of the identity
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * sim_get_username(const u8 *identity, size_t identity_len)
+{
+ char *username;
+ size_t pos;
+
+ if (identity == NULL)
+ return NULL;
+
+ for (pos = 0; pos < identity_len; pos++) {
+ if (identity[pos] == '@' || identity[pos] == '\0')
+ break;
+ }
+
+ username = os_malloc(pos + 1);
+ if (username == NULL)
+ return NULL;
+ os_memcpy(username, identity, pos);
+ username[pos] = '\0';
+
+ return username;
+}
diff --git a/src/eap_server/eap_sim_db.h b/src/eap_server/eap_sim_db.h
index 1f6375a..53a1a7c 100644
--- a/src/eap_server/eap_sim_db.h
+++ b/src/eap_server/eap_sim_db.h
@@ -28,50 +28,47 @@
EAP_SIM_DB_AKA_PRIME
};
-void * eap_sim_db_init(const char *config,
- void (*get_complete_cb)(void *ctx, void *session_ctx),
- void *ctx);
+struct eap_sim_db_data;
+
+struct eap_sim_db_data *
+eap_sim_db_init(const char *config,
+ void (*get_complete_cb)(void *ctx, void *session_ctx),
+ void *ctx);
void eap_sim_db_deinit(void *priv);
-int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
- size_t identity_len, int max_chal,
+int eap_sim_db_get_gsm_triplets(struct eap_sim_db_data *data,
+ const char *username, int max_chal,
u8 *_rand, u8 *kc, u8 *sres,
void *cb_session_ctx);
#define EAP_SIM_DB_FAILURE -1
#define EAP_SIM_DB_PENDING -2
-int eap_sim_db_identity_known(void *priv, const u8 *identity,
- size_t identity_len);
-
-char * eap_sim_db_get_next_pseudonym(void *priv,
+char * eap_sim_db_get_next_pseudonym(struct eap_sim_db_data *data,
enum eap_sim_db_method method);
-char * eap_sim_db_get_next_reauth_id(void *priv,
+char * eap_sim_db_get_next_reauth_id(struct eap_sim_db_data *data,
enum eap_sim_db_method method);
-int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
- size_t identity_len, char *pseudonym);
+int eap_sim_db_add_pseudonym(struct eap_sim_db_data *data,
+ const char *permanent, char *pseudonym);
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id, u16 counter,
- const u8 *mk);
-int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
- size_t identity_len, char *reauth_id,
- u16 counter, const u8 *k_encr, const u8 *k_aut,
- const u8 *k_re);
+int eap_sim_db_add_reauth(struct eap_sim_db_data *data, const char *permanent,
+ char *reauth_id, u16 counter, const u8 *mk);
+int eap_sim_db_add_reauth_prime(struct eap_sim_db_data *data,
+ const char *permanent,
+ char *reauth_id, u16 counter, const u8 *k_encr,
+ const u8 *k_aut, const u8 *k_re);
-const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
- size_t identity_len, size_t *len);
+const char * eap_sim_db_get_permanent(struct eap_sim_db_data *data,
+ const char *pseudonym);
struct eap_sim_reauth {
struct eap_sim_reauth *next;
- u8 *identity;
- size_t identity_len;
- char *reauth_id;
+ char *permanent; /* Permanent username */
+ char *reauth_id; /* Fast re-authentication username */
u16 counter;
- int aka_prime;
u8 mk[EAP_SIM_MK_LEN];
u8 k_encr[EAP_SIM_K_ENCR_LEN];
u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
@@ -79,18 +76,20 @@
};
struct eap_sim_reauth *
-eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
- size_t identity_len);
+eap_sim_db_get_reauth_entry(struct eap_sim_db_data *data,
+ const char *reauth_id);
-void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth);
+void eap_sim_db_remove_reauth(struct eap_sim_db_data *data,
+ struct eap_sim_reauth *reauth);
-int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
- size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
- u8 *ck, u8 *res, size_t *res_len,
- void *cb_session_ctx);
+int eap_sim_db_get_aka_auth(struct eap_sim_db_data *data, const char *username,
+ u8 *_rand, u8 *autn, u8 *ik, u8 *ck,
+ u8 *res, size_t *res_len, void *cb_session_ctx);
-int eap_sim_db_resynchronize(void *priv, const u8 *identity,
- size_t identity_len, const u8 *auts,
+int eap_sim_db_resynchronize(struct eap_sim_db_data *data,
+ const char *username, const u8 *auts,
const u8 *_rand);
+char * sim_get_username(const u8 *identity, size_t identity_len);
+
#endif /* EAP_SIM_DB_H */
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 31fe503..11f5827 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -62,7 +62,12 @@
/* could be up to 128 bytes, but only the first 64 bytes are used */
#define EAP_TLS_KEY_LEN 64
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
+struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+ u8 code, u8 identifier);
int eap_server_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
int verify_peer);
void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 8d6d18f..c3ccb46 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -757,7 +757,8 @@
struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
int flags, const struct wpabuf *assoc_wps_ie,
- const struct wpabuf *assoc_p2p_ie, void *sta_ctx)
+ const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
+ const char *identity, const char *radius_cui)
{
struct eapol_state_machine *sm;
struct eap_config eap_conf;
@@ -838,6 +839,15 @@
eapol_auth_initialize(sm);
+ if (identity) {
+ sm->identity = (u8 *) os_strdup(identity);
+ if (sm->identity)
+ sm->identity_len = os_strlen(identity);
+ }
+ if (radius_cui)
+ sm->radius_cui = wpabuf_alloc_copy(radius_cui,
+ os_strlen(radius_cui));
+
return sm;
}
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 5e8ff43..b50bbdd 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -77,7 +77,8 @@
struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
int flags, const struct wpabuf *assoc_wps_ie,
- const struct wpabuf *assoc_p2p_ie, void *sta_ctx);
+ const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
+ const char *identity, const char *radius_cui);
void eapol_auth_free(struct eapol_state_machine *sm);
void eapol_auth_step(struct eapol_state_machine *sm);
void eapol_auth_dump_state(FILE *f, const char *prefix,
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index f0cae70..851cf49 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -1,6 +1,6 @@
/*
* EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -139,46 +139,6 @@
};
-#define IEEE8021X_REPLAY_COUNTER_LEN 8
-#define IEEE8021X_KEY_SIGN_LEN 16
-#define IEEE8021X_KEY_IV_LEN 16
-
-#define IEEE8021X_KEY_INDEX_FLAG 0x80
-#define IEEE8021X_KEY_INDEX_MASK 0x03
-
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
-
-struct ieee802_1x_eapol_key {
- u8 type;
- /* Note: key_length is unaligned */
- u8 key_length[2];
- /* does not repeat within the life of the keying material used to
- * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
- u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
- u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
- u8 key_index; /* key flag in the most significant bit:
- * 0 = broadcast (default key),
- * 1 = unicast (key mapping key); key index is in the
- * 7 least significant bits */
- /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
- * the key */
- u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
-
- /* followed by key: if packet body length = 44 + key length, then the
- * key field (of key_length bytes) contains the key in encrypted form;
- * if packet body length = 44, key field is absent and key_length
- * represents the number of least significant octets from
- * MS-MPPE-Send-Key attribute to be used as the keying material;
- * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-
static void eapol_sm_txLogoff(struct eapol_sm *sm);
static void eapol_sm_txStart(struct eapol_sm *sm);
static void eapol_sm_processKey(struct eapol_sm *sm);
@@ -664,6 +624,7 @@
static void eapol_sm_processKey(struct eapol_sm *sm)
{
+#ifndef CONFIG_FIPS
struct ieee802_1x_hdr *hdr;
struct ieee802_1x_eapol_key *key;
struct eap_key_data keydata;
@@ -671,6 +632,7 @@
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
int key_len, res, sign_key_len, encr_key_len;
u16 rx_key_length;
+ size_t plen;
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
if (sm->last_rx_key == NULL)
@@ -683,9 +645,12 @@
return;
}
+ if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
+ return;
hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
- if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
+ plen = be_to_host16(hdr->length);
+ if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
return;
}
@@ -751,7 +716,7 @@
}
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
- key_len = be_to_host16(hdr->length) - sizeof(*key);
+ key_len = plen - sizeof(*key);
if (key_len > 32 || rx_key_length > 32) {
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
key_len ? key_len : rx_key_length);
@@ -822,6 +787,7 @@
sm->ctx->eapol_done_cb(sm->ctx->ctx);
}
}
+#endif /* CONFIG_FIPS */
}
@@ -1778,7 +1744,8 @@
switch (variable) {
case EAPOL_idleWhile:
sm->idleWhile = value;
- eapol_enable_timer_tick(sm);
+ if (sm->idleWhile > 0)
+ eapol_enable_timer_tick(sm);
break;
}
}
@@ -1858,6 +1825,15 @@
}
+static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct eapol_sm *sm = ctx;
+
+ if (sm->ctx->set_anon_id)
+ sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
+}
+
+
static struct eapol_callbacks eapol_cb =
{
eapol_sm_get_config,
@@ -1871,7 +1847,8 @@
eapol_sm_notify_pending,
eapol_sm_eap_param_needed,
eapol_sm_notify_cert,
- eapol_sm_notify_status
+ eapol_sm_notify_status,
+ eapol_sm_set_anon_id
};
@@ -1946,3 +1923,19 @@
os_free(sm->ctx);
os_free(sm);
}
+
+
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext)
+{
+ if (sm && sm->eap)
+ eap_sm_set_ext_pw_ctx(sm->eap, ext);
+}
+
+
+int eapol_sm_failed(struct eapol_sm *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return !sm->eapSuccess && sm->eapFail;
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 1a20e4b..c4b87da 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -1,6 +1,6 @@
/*
* EAPOL supplicant state machines
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -239,10 +239,19 @@
*/
void (*status_cb)(void *ctx, const char *status,
const char *parameter);
+
+ /**
+ * set_anon_id - Set or add anonymous identity
+ * @ctx: eapol_ctx from eap_peer_sm_init() call
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym)
+ * @len: Length of anonymous identity in octets
+ */
+ void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
};
struct eap_peer_config;
+struct ext_password_data;
#ifdef IEEE8021X_EAPOL
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx);
@@ -275,6 +284,9 @@
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm);
void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
const char * eapol_sm_get_method_name(struct eapol_sm *sm);
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext);
+int eapol_sm_failed(struct eapol_sm *sm);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
@@ -366,6 +378,14 @@
{
return NULL;
}
+static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+ struct ext_password_data *ext)
+{
+}
+static inline int eapol_sm_failed(struct eapol_sm *sm)
+{
+ return 0;
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SUPP_SM_H */
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index eb2821e..03380dc 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -172,6 +172,8 @@
return "INVITE_LISTEN";
case P2P_SEARCH_WHEN_READY:
return "SEARCH_WHEN_READY";
+ case P2P_CONTINUE_SEARCH_WHEN_READY:
+ return "CONTINUE_SEARCH_WHEN_READY";
default:
return "?";
}
@@ -725,6 +727,11 @@
break;
}
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
if (scan_res) {
p2p_add_group_clients(p2p, p2p_dev_addr, addr, freq,
msg.group_info, msg.group_info_len);
@@ -782,6 +789,8 @@
dev->info.wps_vendor_ext[i] = NULL;
}
+ wpabuf_free(dev->info.wfd_subelems);
+
os_free(dev);
}
@@ -846,6 +855,7 @@
int freq = 0;
enum p2p_scan_type type;
u16 pw_id = DEV_PW_DEFAULT;
+ int res;
if (p2p->drv_in_listen) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Driver is still "
@@ -865,12 +875,18 @@
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting search");
}
- if (p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
- p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id, pw_id)) {
+ res = p2p->cfg->p2p_scan(p2p->cfg->cb_ctx, type, freq,
+ p2p->num_req_dev_types, p2p->req_dev_types,
+ p2p->find_dev_id, pw_id);
+ if (res < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Scan request failed");
p2p_continue_find(p2p);
+ } else if (res == 1) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+ "p2p_scan at this point - will try again after "
+ "previous scan completes");
+ p2p_set_state(p2p, P2P_CONTINUE_SEARCH_WHEN_READY);
} else {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Running p2p_scan");
p2p->p2p_scan_running = 1;
@@ -975,7 +991,7 @@
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id)
+ const u8 *dev_id, unsigned int search_delay)
{
int res;
@@ -1009,6 +1025,8 @@
p2p->find_type = type;
p2p_device_clear_reported(p2p);
p2p_set_state(p2p, P2P_SEARCH);
+ p2p->search_delay = search_delay;
+ p2p->in_search_delay = 0;
eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
p2p->last_p2p_find_timeout = timeout;
if (timeout)
@@ -1070,13 +1088,18 @@
int p2p_other_scan_completed(struct p2p_data *p2p)
{
+ if (p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY) {
+ p2p_set_state(p2p, P2P_SEARCH);
+ p2p_search(p2p);
+ return 1;
+ }
if (p2p->state != P2P_SEARCH_WHEN_READY)
return 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
"now that previous scan was completed");
if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
p2p->num_req_dev_types, p2p->req_dev_types,
- p2p->find_dev_id) < 0)
+ p2p->find_dev_id, p2p->search_delay) < 0)
return 0;
return 1;
}
@@ -1442,6 +1465,11 @@
}
}
+ if (msg->wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg->wfd_subelems);
+ }
+
if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) {
dev->flags &= ~P2P_DEV_PROBE_REQ_ONLY;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1779,6 +1807,11 @@
p2p_copy_wps_info(dev, 1, &msg);
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
p2p_parse_free(&msg);
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1877,8 +1910,14 @@
struct wpabuf *buf;
u8 *len;
int pw_id = -1;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_probe_resp)
+ extra = wpabuf_len(p2p->wfd_ie_probe_resp);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -1889,6 +1928,11 @@
p2p_build_wps_ie(p2p, buf, pw_id, 1);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_probe_resp)
+ wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp);
+#endif /* CONFIG_WIFI_DISPLAY */
+
/* P2P IE */
len = p2p_buf_add_ie_hdr(buf);
p2p_buf_add_capability(buf, p2p->dev_capab &
@@ -2173,20 +2217,31 @@
struct p2p_device *peer;
size_t tmplen;
int res;
+ size_t extra = 0;
if (!p2p_group)
return p2p_assoc_req_ie_wlan_ap(p2p, bssid, buf, len, p2p_ie);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_assoc_req)
+ extra = wpabuf_len(p2p->wfd_ie_assoc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
/*
* (Re)Association Request - P2P IE
* P2P Capability attribute (shall be present)
* Extended Listen Timing (may be present)
* P2P Device Info attribute (shall be present)
*/
- tmp = wpabuf_alloc(200);
+ tmp = wpabuf_alloc(200 + extra);
if (tmp == NULL)
return -1;
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_assoc_req)
+ wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
peer = bssid ? p2p_get_device(p2p, bssid) : NULL;
lpos = p2p_buf_add_ie_hdr(tmp);
@@ -2370,12 +2425,29 @@
eloop_register_timeout(P2P_PEER_EXPIRATION_INTERVAL, 0,
p2p_expiration_timeout, p2p, NULL);
+ p2p->go_timeout = 100;
+ p2p->client_timeout = 20;
+
return p2p;
}
void p2p_deinit(struct p2p_data *p2p)
{
+#ifdef CONFIG_WIFI_DISPLAY
+ wpabuf_free(p2p->wfd_ie_beacon);
+ wpabuf_free(p2p->wfd_ie_probe_req);
+ wpabuf_free(p2p->wfd_ie_probe_resp);
+ wpabuf_free(p2p->wfd_ie_assoc_req);
+ wpabuf_free(p2p->wfd_ie_invitation);
+ wpabuf_free(p2p->wfd_ie_prov_disc_req);
+ wpabuf_free(p2p->wfd_ie_prov_disc_resp);
+ wpabuf_free(p2p->wfd_ie_go_neg);
+ wpabuf_free(p2p->wfd_dev_info);
+ wpabuf_free(p2p->wfd_assoc_bssid);
+ wpabuf_free(p2p->wfd_coupled_sink_info);
+#endif /* CONFIG_WIFI_DISPLAY */
+
eloop_cancel_timeout(p2p_expiration_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
@@ -2723,7 +2795,13 @@
if (!success) {
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
- if (p2p->state != P2P_IDLE)
+ if (p2p->user_initiated_pd &&
+ (p2p->state == P2P_SEARCH || p2p->state == P2P_LISTEN_ONLY))
+ {
+ /* Retry request from timeout to avoid busy loops */
+ p2p->pending_action_state = P2P_PENDING_PD;
+ p2p_set_timeout(p2p, 0, 50000);
+ } else if (p2p->state != P2P_IDLE)
p2p_continue_find(p2p);
else if (p2p->user_initiated_pd) {
p2p->pending_action_state = P2P_PENDING_PD;
@@ -2775,7 +2853,14 @@
void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id)
{
- u8 *len = p2p_buf_add_ie_hdr(ies);
+ u8 *len;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_probe_req)
+ wpabuf_put_buf(ies, p2p->wfd_ie_probe_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ len = p2p_buf_add_ie_hdr(ies);
p2p_buf_add_capability(ies, p2p->dev_capab &
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0);
if (dev_id)
@@ -2794,7 +2879,14 @@
size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
{
- return 100;
+ size_t len = 100;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p && p2p->wfd_ie_probe_req)
+ len += wpabuf_len(p2p->wfd_ie_probe_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ return len;
}
@@ -2845,7 +2937,7 @@
* channel.
*/
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, success ? 200000 : 100000);
}
@@ -2861,7 +2953,7 @@
return;
}
p2p_set_state(p2p, P2P_CONNECT);
- p2p_set_timeout(p2p, 0, 100000);
+ p2p_set_timeout(p2p, 0, 250000);
}
@@ -3056,6 +3148,14 @@
p2p_set_timeout(p2p, 0, 100000);
return 1;
}
+ if (p2p->search_delay) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
+ "search operation by %u ms",
+ p2p->search_delay);
+ p2p_set_timeout(p2p, p2p->search_delay / 1000,
+ (p2p->search_delay % 1000) * 1000);
+ return 1;
+ }
p2p_search(p2p);
return 1;
}
@@ -3250,6 +3350,16 @@
/* Check if we timed out waiting for PD req */
if (p2p->pending_action_state == P2P_PENDING_PD)
p2p_timeout_prov_disc_req(p2p);
+ if (p2p->search_delay && !p2p->in_search_delay) {
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Delay "
+ "search operation by %u ms",
+ p2p->search_delay);
+ p2p->in_search_delay = 1;
+ p2p_set_timeout(p2p, p2p->search_delay / 1000,
+ (p2p->search_delay % 1000) * 1000);
+ break;
+ }
+ p2p->in_search_delay = 0;
p2p_search(p2p);
break;
case P2P_CONNECT:
@@ -3295,6 +3405,8 @@
break;
case P2P_SEARCH_WHEN_READY:
break;
+ case P2P_CONTINUE_SEARCH_WHEN_READY:
+ break;
}
}
@@ -3478,6 +3590,24 @@
pos += res;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (dev->info.wfd_subelems) {
+ res = os_snprintf(pos, end - pos, "wfd_subelems=");
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(dev->info.wfd_subelems),
+ wpabuf_len(dev->info.wfd_subelems));
+
+ res = os_snprintf(pos, end - pos, "\n");
+ if (res < 0 || res >= end - pos)
+ return pos - buf;
+ pos += res;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return pos - buf;
}
@@ -4085,5 +4215,150 @@
{
if (p2p == NULL)
return 0;
+ if (p2p->state == P2P_SEARCH || p2p->state == P2P_SEARCH_WHEN_READY ||
+ p2p->state == P2P_CONTINUE_SEARCH_WHEN_READY)
+ return 2;
return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
}
+
+
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+ u8 client_timeout)
+{
+ if (p2p) {
+ p2p->go_timeout = go_timeout;
+ p2p->client_timeout = client_timeout;
+ }
+}
+
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay)
+{
+ if (p2p && p2p->search_delay < delay)
+ p2p->search_delay = delay;
+}
+
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static void p2p_update_wfd_ie_groups(struct p2p_data *p2p)
+{
+ size_t g;
+ struct p2p_group *group;
+
+ for (g = 0; g < p2p->num_groups; g++) {
+ group = p2p->groups[g];
+ p2p_group_update_ies(group);
+ }
+}
+
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_beacon);
+ p2p->wfd_ie_beacon = ie;
+ p2p_update_wfd_ie_groups(p2p);
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_probe_req);
+ p2p->wfd_ie_probe_req = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_probe_resp);
+ p2p->wfd_ie_probe_resp = ie;
+ p2p_update_wfd_ie_groups(p2p);
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_assoc_req);
+ p2p->wfd_ie_assoc_req = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_invitation);
+ p2p->wfd_ie_invitation = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_prov_disc_req);
+ p2p->wfd_ie_prov_disc_req = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_prov_disc_resp);
+ p2p->wfd_ie_prov_disc_resp = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie)
+{
+ wpabuf_free(p2p->wfd_ie_go_neg);
+ p2p->wfd_ie_go_neg = ie;
+ return 0;
+}
+
+
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_dev_info);
+ if (elem) {
+ p2p->wfd_dev_info = wpabuf_dup(elem);
+ if (p2p->wfd_dev_info == NULL)
+ return -1;
+ } else
+ p2p->wfd_dev_info = NULL;
+
+ return 0;
+}
+
+
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_assoc_bssid);
+ if (elem) {
+ p2p->wfd_assoc_bssid = wpabuf_dup(elem);
+ if (p2p->wfd_assoc_bssid == NULL)
+ return -1;
+ } else
+ p2p->wfd_assoc_bssid = NULL;
+
+ return 0;
+}
+
+
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+ const struct wpabuf *elem)
+{
+ wpabuf_free(p2p->wfd_coupled_sink_info);
+ if (elem) {
+ p2p->wfd_coupled_sink_info = wpabuf_dup(elem);
+ if (p2p->wfd_coupled_sink_info == NULL)
+ return -1;
+ } else
+ p2p->wfd_coupled_sink_info = NULL;
+
+ return 0;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 59da452..b80f898 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -79,6 +79,8 @@
*/
int freq;
+ int ht40;
+
/**
* ssid - SSID of the group
*/
@@ -214,6 +216,11 @@
size_t wps_sec_dev_type_list_len;
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+ /**
+ * wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
+ */
+ struct wpabuf *wfd_subelems;
};
enum p2p_prov_disc_status {
@@ -841,12 +848,13 @@
* containing num_req_dev_types * WPS_DEV_TYPE_LEN bytes; %NULL if no
* requested device types.
* @dev_id: Device ID to search for or %NULL to find all devices
+ * @search_delay: Extra delay in milliseconds between search iterations
* Returns: 0 on success, -1 on failure
*/
int p2p_find(struct p2p_data *p2p, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id);
+ const u8 *dev_id, unsigned int search_delay);
/**
* p2p_stop_find - Stop P2P Find (Device Discovery)
@@ -969,6 +977,11 @@
void * p2p_sd_request(struct p2p_data *p2p, const u8 *dst,
const struct wpabuf *tlvs);
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+ const struct wpabuf *tlvs);
+#endif /* CONFIG_WIFI_DISPLAY */
+
/**
* p2p_sd_cancel_request - Cancel a pending service discovery query
* @p2p: P2P module context from p2p_init()
@@ -1729,4 +1742,29 @@
const char * p2p_wps_method_text(enum p2p_wps_method method);
+/**
+ * p2p_set_config_timeout - Set local config timeouts
+ * @p2p: P2P module context from p2p_init()
+ * @go_timeout: Time in 10 ms units it takes to start the GO mode
+ * @client_timeout: Time in 10 ms units it takes to start the client mode
+ */
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+ u8 client_timeout);
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+ const struct wpabuf *elem);
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 248b2a0..031b3a1 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -134,8 +134,14 @@
struct wpabuf *buf;
u8 *len;
u8 group_capab;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -161,7 +167,7 @@
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) |
p2p->next_tie_breaker);
p2p->next_tie_breaker = !p2p->next_tie_breaker;
- p2p_buf_add_config_timeout(buf, 100, 20);
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
p2p_buf_add_listen_channel(buf, p2p->cfg->country, p2p->cfg->reg_class,
p2p->cfg->channel);
if (p2p->ext_listen_interval)
@@ -177,6 +183,11 @@
/* WPS IE with Device Password ID attribute */
p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
@@ -246,10 +257,17 @@
struct wpabuf *buf;
u8 *len;
u8 group_capab;
+ size_t extra = 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Building GO Negotiation Response");
- buf = wpabuf_alloc(1000);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -274,7 +292,7 @@
~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY,
group_capab);
p2p_buf_add_go_intent(buf, (p2p->go_intent << 1) | tie_breaker);
- p2p_buf_add_config_timeout(buf, 100, 20);
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout, p2p->client_timeout);
if (peer && peer->go_state == REMOTE_GO) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Omit Operating "
"Channel attribute");
@@ -308,6 +326,12 @@
p2p_wps_method_pw_id(peer ? peer->wps_method :
WPS_NOT_READY), 0);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
return buf;
}
@@ -692,7 +716,7 @@
P2P_PENDING_GO_NEG_RESPONSE_FAILURE;
if (p2p_send_action(p2p, freq, sa, p2p->cfg->dev_addr,
p2p->cfg->dev_addr,
- wpabuf_head(resp), wpabuf_len(resp), 200) < 0) {
+ wpabuf_head(resp), wpabuf_len(resp), 250) < 0) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Failed to send Action frame");
}
@@ -710,10 +734,17 @@
u8 *len;
struct p2p_channels res;
u8 group_capab;
+ size_t extra = 0;
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Building GO Negotiation Confirm");
- buf = wpabuf_alloc(1000);
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ extra = wpabuf_len(p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -752,6 +783,11 @@
}
p2p_buf_update_ie_hdr(buf, len);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_go_neg)
+ wpabuf_put_buf(buf, p2p->wfd_ie_go_neg);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 8d4a3cb..8687320 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -22,6 +22,7 @@
u8 addr[ETH_ALEN]; /* P2P Interface Address */
u8 dev_addr[ETH_ALEN]; /* P2P Device Address */
struct wpabuf *p2p_ie;
+ struct wpabuf *wfd_ie;
struct wpabuf *client_info;
u8 dev_capab;
};
@@ -37,12 +38,10 @@
int group_formation;
int beacon_update;
struct wpabuf *noa;
+ struct wpabuf *wfd_ie;
};
-static void p2p_group_update_ies(struct p2p_group *group);
-
-
struct p2p_group * p2p_group_init(struct p2p_data *p2p,
struct p2p_group_config *config)
{
@@ -52,8 +51,8 @@
if (group == NULL)
return NULL;
- groups = os_realloc(p2p->groups, (p2p->num_groups + 1) *
- sizeof(struct p2p_group *));
+ groups = os_realloc_array(p2p->groups, p2p->num_groups + 1,
+ sizeof(struct p2p_group *));
if (groups == NULL) {
os_free(group);
return NULL;
@@ -74,6 +73,7 @@
static void p2p_group_free_member(struct p2p_group_member *m)
{
+ wpabuf_free(m->wfd_ie);
wpabuf_free(m->p2p_ie);
wpabuf_free(m->client_info);
os_free(m);
@@ -118,6 +118,7 @@
p2p_group_free_members(group);
os_free(group->cfg);
wpabuf_free(group->noa);
+ wpabuf_free(group->wfd_ie);
os_free(group);
}
@@ -172,11 +173,22 @@
{
struct wpabuf *ie;
u8 *len;
+ size_t extra = 0;
- ie = wpabuf_alloc(257);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->p2p->wfd_ie_beacon)
+ extra = wpabuf_len(group->p2p->wfd_ie_beacon);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->p2p->wfd_ie_beacon)
+ wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon);
+#endif /* CONFIG_WIFI_DISPLAY */
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
@@ -187,17 +199,193 @@
}
+#ifdef CONFIG_WIFI_DISPLAY
+
+struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g)
+{
+ return g->wfd_ie;
+}
+
+
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems)
+{
+ struct wpabuf *ie;
+ const u8 *pos, *end;
+
+ if (subelems == NULL)
+ return NULL;
+
+ ie = wpabuf_alloc(wpabuf_len(subelems) + 100);
+ if (ie == NULL)
+ return NULL;
+
+ pos = wpabuf_head(subelems);
+ end = pos + wpabuf_len(subelems);
+
+ while (end > pos) {
+ size_t frag_len = end - pos;
+ if (frag_len > 251)
+ frag_len = 251;
+ wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+ wpabuf_put_u8(ie, 4 + frag_len);
+ wpabuf_put_be32(ie, WFD_IE_VENDOR_TYPE);
+ wpabuf_put_data(ie, pos, frag_len);
+ pos += frag_len;
+ }
+
+ return ie;
+}
+
+
+static int wifi_display_add_dev_info_descr(struct wpabuf *buf,
+ struct p2p_group_member *m)
+{
+ const u8 *pos, *end;
+ const u8 *dev_info = NULL;
+ const u8 *assoc_bssid = NULL;
+ const u8 *coupled_sink = NULL;
+ u8 zero_addr[ETH_ALEN];
+
+ if (m->wfd_ie == NULL)
+ return 0;
+
+ os_memset(zero_addr, 0, ETH_ALEN);
+ pos = wpabuf_head_u8(m->wfd_ie);
+ end = pos + wpabuf_len(m->wfd_ie);
+ while (pos + 1 < end) {
+ u8 id;
+ u16 len;
+
+ id = *pos++;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end)
+ break;
+
+ switch (id) {
+ case WFD_SUBELEM_DEVICE_INFO:
+ if (len < 6)
+ break;
+ dev_info = pos;
+ break;
+ case WFD_SUBELEM_ASSOCIATED_BSSID:
+ if (len < ETH_ALEN)
+ break;
+ assoc_bssid = pos;
+ break;
+ case WFD_SUBELEM_COUPLED_SINK:
+ if (len < 1 + ETH_ALEN)
+ break;
+ coupled_sink = pos;
+ break;
+ }
+
+ pos += len;
+ }
+
+ if (dev_info == NULL)
+ return 0;
+
+ wpabuf_put_u8(buf, 23);
+ wpabuf_put_data(buf, m->dev_addr, ETH_ALEN);
+ if (assoc_bssid)
+ wpabuf_put_data(buf, assoc_bssid, ETH_ALEN);
+ else
+ wpabuf_put_data(buf, zero_addr, ETH_ALEN);
+ wpabuf_put_data(buf, dev_info, 2); /* WFD Device Info */
+ wpabuf_put_data(buf, dev_info + 4, 2); /* WFD Device Max Throughput */
+ if (coupled_sink) {
+ wpabuf_put_data(buf, coupled_sink, 1 + ETH_ALEN);
+ } else {
+ wpabuf_put_u8(buf, 0);
+ wpabuf_put_data(buf, zero_addr, ETH_ALEN);
+ }
+
+ return 1;
+}
+
+
+static struct wpabuf *
+wifi_display_build_go_ie(struct p2p_group *group)
+{
+ struct wpabuf *wfd_subelems, *wfd_ie;
+ struct p2p_group_member *m;
+ u8 *len;
+ unsigned int count = 0;
+
+ if (!group->p2p->wfd_ie_probe_resp)
+ return NULL;
+
+ wfd_subelems = wpabuf_alloc(wpabuf_len(group->p2p->wfd_ie_probe_resp) +
+ group->num_members * 24 + 100);
+ if (wfd_subelems == NULL)
+ return NULL;
+ if (group->p2p->wfd_dev_info)
+ wpabuf_put_buf(wfd_subelems, group->p2p->wfd_dev_info);
+ if (group->p2p->wfd_assoc_bssid)
+ wpabuf_put_buf(wfd_subelems,
+ group->p2p->wfd_assoc_bssid);
+ if (group->p2p->wfd_coupled_sink_info)
+ wpabuf_put_buf(wfd_subelems,
+ group->p2p->wfd_coupled_sink_info);
+
+ /* Build WFD Session Info */
+ wpabuf_put_u8(wfd_subelems, WFD_SUBELEM_SESSION_INFO);
+ len = wpabuf_put(wfd_subelems, 2);
+ m = group->members;
+ while (m) {
+ if (wifi_display_add_dev_info_descr(wfd_subelems, m))
+ count++;
+ m = m->next;
+ }
+
+ if (count == 0) {
+ /* No Wi-Fi Display clients - do not include subelement */
+ wfd_subelems->used -= 3;
+ } else {
+ WPA_PUT_BE16(len, (u8 *) wpabuf_put(wfd_subelems, 0) - len -
+ 2);
+ wpa_printf(MSG_DEBUG, "WFD: WFD Session Info: %u descriptors",
+ count);
+ }
+
+ wfd_ie = wifi_display_encaps(wfd_subelems);
+ wpabuf_free(wfd_subelems);
+
+ return wfd_ie;
+}
+
+static void wifi_display_group_update(struct p2p_group *group)
+{
+ wpabuf_free(group->wfd_ie);
+ group->wfd_ie = wifi_display_build_go_ie(group);
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group)
{
u8 *group_info;
struct wpabuf *ie;
struct p2p_group_member *m;
u8 *len;
+ size_t extra = 0;
- ie = wpabuf_alloc(257);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ extra += wpabuf_len(group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ ie = wpabuf_alloc(257 + extra);
if (ie == NULL)
return NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ wpabuf_put_buf(ie, group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
len = p2p_buf_add_ie_hdr(ie);
p2p_group_add_common_ies(group, ie);
@@ -216,15 +404,20 @@
(u8 *) wpabuf_put(ie, 0) - group_info - 3);
p2p_buf_update_ie_hdr(ie, len);
+
return ie;
}
-static void p2p_group_update_ies(struct p2p_group *group)
+void p2p_group_update_ies(struct p2p_group *group)
{
struct wpabuf *beacon_ie;
struct wpabuf *probe_resp_ie;
+#ifdef CONFIG_WIFI_DISPLAY
+ wifi_display_group_update(group);
+#endif /* CONFIG_WIFI_DISPLAY */
+
probe_resp_ie = p2p_group_build_probe_resp_ie(group);
if (probe_resp_ie == NULL)
return;
@@ -354,6 +547,9 @@
&m->dev_capab,
m->dev_addr);
}
+#ifdef CONFIG_WIFI_DISPLAY
+ m->wfd_ie = ieee802_11_vendor_ie_concat(ie, len, WFD_IE_VENDOR_TYPE);
+#endif /* CONFIG_WIFI_DISPLAY */
p2p_group_remove_member(group, addr);
@@ -361,8 +557,9 @@
group->members = m;
group->num_members++;
wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Add client " MACSTR
- " to group (p2p=%d client_info=%d); num_members=%u/%u",
- MAC2STR(addr), m->p2p_ie ? 1 : 0, m->client_info ? 1 : 0,
+ " to group (p2p=%d wfd=%d client_info=%d); num_members=%u/%u",
+ MAC2STR(addr), m->p2p_ie ? 1 : 0, m->wfd_ie ? 1 : 0,
+ m->client_info ? 1 : 0,
group->num_members, group->cfg->max_clients);
if (group->num_members == group->cfg->max_clients)
group->beacon_update = 1;
@@ -378,6 +575,12 @@
{
struct wpabuf *resp;
u8 *rlen;
+ size_t extra = 0;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ extra = wpabuf_len(group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
/*
* (Re)Association Response - P2P IE
@@ -385,9 +588,15 @@
* denied)
* Extended Listen Timing (may be present)
*/
- resp = wpabuf_alloc(20);
+ resp = wpabuf_alloc(20 + extra);
if (resp == NULL)
return NULL;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (group->wfd_ie)
+ wpabuf_put_buf(resp, group->wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
rlen = p2p_buf_add_ie_hdr(resp);
if (status != P2P_SC_SUCCESS)
p2p_buf_add_status(resp, status);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index b0abff0..bf55015 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -109,6 +109,7 @@
struct p2p_sd_query *next;
u8 peer[ETH_ALEN];
int for_all_peers;
+ int wsd; /* Wi-Fi Display Service Discovery Request */
struct wpabuf *tlvs;
};
@@ -207,6 +208,11 @@
* P2P_SEARCH_WHEN_READY - Waiting to start Search
*/
P2P_SEARCH_WHEN_READY,
+
+ /**
+ * P2P_CONTINUE_SEARCH_WHEN_READY - Waiting to continue Search
+ */
+ P2P_CONTINUE_SEARCH_WHEN_READY,
} state;
/**
@@ -437,6 +443,27 @@
* in IDLE state.
*/
int pd_retries;
+
+ u8 go_timeout;
+ u8 client_timeout;
+
+ /* Extra delay in milliseconds between search iterations */
+ unsigned int search_delay;
+ int in_search_delay;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie_beacon;
+ struct wpabuf *wfd_ie_probe_req;
+ struct wpabuf *wfd_ie_probe_resp;
+ struct wpabuf *wfd_ie_assoc_req;
+ struct wpabuf *wfd_ie_invitation;
+ struct wpabuf *wfd_ie_prov_disc_req;
+ struct wpabuf *wfd_ie_prov_disc_resp;
+ struct wpabuf *wfd_ie_go_neg;
+ struct wpabuf *wfd_dev_info;
+ struct wpabuf *wfd_assoc_bssid;
+ struct wpabuf *wfd_coupled_sink_info;
+#endif /* CONFIG_WIFI_DISPLAY */
};
/**
@@ -445,6 +472,7 @@
struct p2p_message {
struct wpabuf *p2p_attributes;
struct wpabuf *wps_attributes;
+ struct wpabuf *wfd_subelems;
u8 dialog_token;
@@ -565,6 +593,8 @@
const u8 *noa, size_t noa_len);
int p2p_group_is_group_id_match(struct p2p_group *group, const u8 *group_id,
size_t group_id_len);
+void p2p_group_update_ies(struct p2p_group *group);
+struct wpabuf * p2p_group_get_wfd_ie(struct p2p_group *g);
void p2p_buf_add_action_hdr(struct wpabuf *buf, u8 subtype, u8 dialog_token);
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 5925549..d26654b 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -21,8 +21,30 @@
struct wpabuf *buf;
u8 *len;
const u8 *dev_addr;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
+ if (wfd_ie && p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ struct p2p_group *g = p2p->groups[i];
+ struct wpabuf *ie;
+ if (os_memcmp(p2p_group_get_interface_addr(g),
+ p2p->inv_bssid, ETH_ALEN) != 0)
+ continue;
+ ie = p2p_group_get_wfd_ie(g);
+ if (ie) {
+ wfd_ie = ie;
+ break;
+ }
+ }
+ }
+ if (wfd_ie)
+ extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -36,7 +58,8 @@
if (p2p->inv_role == P2P_INVITE_ROLE_ACTIVE_GO || !p2p->inv_persistent)
p2p_buf_add_config_timeout(buf, 0, 0);
else
- p2p_buf_add_config_timeout(buf, 100, 20);
+ p2p_buf_add_config_timeout(buf, p2p->go_timeout,
+ p2p->client_timeout);
p2p_buf_add_invitation_flags(buf, p2p->inv_persistent ?
P2P_INVITATION_FLAGS_TYPE : 0);
p2p_buf_add_operating_channel(buf, p2p->cfg->country,
@@ -54,6 +77,11 @@
p2p_buf_add_device_info(buf, p2p, peer);
p2p_buf_update_ie_hdr(buf, len);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_ie)
+ wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
@@ -67,8 +95,30 @@
{
struct wpabuf *buf;
u8 *len;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie = p2p->wfd_ie_invitation;
+ if (wfd_ie && group_bssid) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ struct p2p_group *g = p2p->groups[i];
+ struct wpabuf *ie;
+ if (os_memcmp(p2p_group_get_interface_addr(g),
+ group_bssid, ETH_ALEN) != 0)
+ continue;
+ ie = p2p_group_get_wfd_ie(g);
+ if (ie) {
+ wfd_ie = ie;
+ break;
+ }
+ }
+ }
+ if (wfd_ie)
+ extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -87,6 +137,11 @@
p2p_buf_add_channel_list(buf, p2p->cfg->country, channels);
p2p_buf_update_ie_hdr(buf, len);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_ie)
+ wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index a3ec57d..097a31d 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -414,6 +414,13 @@
return -1;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (elems.wfd) {
+ msg->wfd_subelems = ieee802_11_vendor_ie_concat(
+ data, len, WFD_IE_VENDOR_TYPE);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return 0;
}
@@ -453,6 +460,10 @@
msg->p2p_attributes = NULL;
wpabuf_free(msg->wps_attributes);
msg->wps_attributes = NULL;
+#ifdef CONFIG_WIFI_DISPLAY
+ wpabuf_free(msg->wfd_subelems);
+ msg->wfd_subelems = NULL;
+#endif /* CONFIG_WIFI_DISPLAY */
}
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 38a9dd8..a2d5aee 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -16,8 +16,8 @@
/*
- * Number of retries to attempt for provision discovery requests during IDLE
- * state in case the peer is not listening.
+ * Number of retries to attempt for provision discovery requests
+ * in case the peer is not listening.
*/
#define MAX_PROV_DISC_REQ_RETRIES 10
@@ -46,8 +46,14 @@
{
struct wpabuf *buf;
u8 *len;
+ size_t extra = 0;
- buf = wpabuf_alloc(1000);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_prov_disc_req)
+ extra = wpabuf_len(p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(1000 + extra);
if (buf == NULL)
return NULL;
@@ -66,17 +72,46 @@
/* WPS IE with Config Methods attribute */
p2p_build_wps_ie_config_methods(buf, config_methods);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (p2p->wfd_ie_prov_disc_req)
+ wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p,
u8 dialog_token,
- u16 config_methods)
+ u16 config_methods,
+ const u8 *group_id,
+ size_t group_id_len)
{
struct wpabuf *buf;
+ size_t extra = 0;
- buf = wpabuf_alloc(100);
+#ifdef CONFIG_WIFI_DISPLAY
+ struct wpabuf *wfd_ie = p2p->wfd_ie_prov_disc_resp;
+ if (wfd_ie && group_id) {
+ size_t i;
+ for (i = 0; i < p2p->num_groups; i++) {
+ struct p2p_group *g = p2p->groups[i];
+ struct wpabuf *ie;
+ if (!p2p_group_is_group_id_match(g, group_id,
+ group_id_len))
+ continue;
+ ie = p2p_group_get_wfd_ie(g);
+ if (ie) {
+ wfd_ie = ie;
+ break;
+ }
+ }
+ }
+ if (wfd_ie)
+ extra = wpabuf_len(wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+ buf = wpabuf_alloc(100 + extra);
if (buf == NULL)
return NULL;
@@ -85,6 +120,11 @@
/* WPS IE with Config Methods attribute */
p2p_build_wps_ie_config_methods(buf, config_methods);
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_ie)
+ wpabuf_put_buf(buf, wfd_ie);
+#endif /* CONFIG_WIFI_DISPLAY */
+
return buf;
}
@@ -117,6 +157,9 @@
"P2P: Provision Discovery Request add device "
"failed " MACSTR, MAC2STR(sa));
}
+ } else if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
if (!(msg.wps_config_methods &
@@ -162,7 +205,8 @@
out:
resp = p2p_build_prov_disc_resp(p2p, msg.dialog_token,
- reject ? 0 : msg.wps_config_methods);
+ reject ? 0 : msg.wps_config_methods,
+ msg.group_id, msg.group_id_len);
if (resp == NULL) {
p2p_parse_free(&msg);
return;
@@ -408,8 +452,7 @@
*/
p2p->user_initiated_pd = !join;
- /* Also set some retries to attempt in case of IDLE state */
- if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+ if (p2p->user_initiated_pd)
p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 7a59f10..bf75605 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -15,15 +15,55 @@
#include "p2p.h"
+#ifdef CONFIG_WIFI_DISPLAY
+static int wfd_wsd_supported(struct wpabuf *wfd)
+{
+ const u8 *pos, *end;
+ u8 subelem;
+ u16 len;
+
+ if (wfd == NULL)
+ return 0;
+
+ pos = wpabuf_head(wfd);
+ end = pos + wpabuf_len(wfd);
+
+ while (pos + 3 <= end) {
+ subelem = *pos++;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (pos + len > end)
+ break;
+
+ if (subelem == WFD_SUBELEM_DEVICE_INFO && len >= 6) {
+ u16 info = WPA_GET_BE16(pos);
+ return !!(info & 0x0040);
+ }
+
+ pos += len;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
struct p2p_device *dev)
{
struct p2p_sd_query *q;
+ int wsd = 0;
if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
return NULL; /* peer does not support SD */
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wfd_wsd_supported(dev->info.wfd_subelems))
+ wsd = 1;
+#endif /* CONFIG_WIFI_DISPLAY */
for (q = p2p->sd_queries; q; q = q->next) {
+ /* Use WSD only if the peer indicates support or it */
+ if (q->wsd && !wsd)
+ continue;
if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
return q;
if (!q->for_all_peers &&
@@ -420,7 +460,7 @@
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
#endif
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Ignore unexpected GAS Initial Response from "
MACSTR, MAC2STR(sa));
return;
@@ -670,7 +710,7 @@
if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL ||
#endif
os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) {
- wpa_msg(p2p->cfg->msg_ctx, MSG_INFO,
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Ignore unexpected GAS Comeback Response from "
MACSTR, MAC2STR(sa));
return;
@@ -907,6 +947,19 @@
}
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+ const struct wpabuf *tlvs)
+{
+ struct p2p_sd_query *q;
+ q = p2p_sd_request(p2p, dst, tlvs);
+ if (q)
+ q->wsd = 1;
+ return q;
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
#ifdef ANDROID_P2P
void p2p_sd_service_update(struct p2p_data *p2p, int action)
#else
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 2b9cbca..d5edfd8 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -78,8 +78,8 @@
static int radius_msg_initialize(struct radius_msg *msg)
{
- msg->attr_pos =
- os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
+ msg->attr_pos = os_calloc(RADIUS_DEFAULT_ATTR_COUNT,
+ sizeof(*msg->attr_pos));
if (msg->attr_pos == NULL)
return -1;
@@ -269,7 +269,7 @@
printf(" Attribute %d (%s) length=%d\n",
hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
- if (attr == NULL)
+ if (attr == NULL || hdr->length < sizeof(struct radius_attr_hdr))
return;
len = hdr->length - sizeof(struct radius_attr_hdr);
@@ -332,7 +332,7 @@
printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
msg->hdr->code, radius_code_string(msg->hdr->code),
- msg->hdr->identifier, ntohs(msg->hdr->length));
+ msg->hdr->identifier, be_to_host16(msg->hdr->length));
for (i = 0; i < msg->attr_used; i++) {
struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
@@ -357,11 +357,11 @@
"Message-Authenticator");
return -1;
}
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
wpabuf_len(msg->buf), (u8 *) (attr + 1));
} else
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
if (wpabuf_len(msg->buf) > 0xffff) {
wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
@@ -387,7 +387,7 @@
printf("WARNING: Could not add Message-Authenticator\n");
return -1;
}
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memcpy(msg->hdr->authenticator, req_authenticator,
sizeof(msg->hdr->authenticator));
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
@@ -430,7 +430,7 @@
return -1;
}
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
wpabuf_len(msg->buf), (u8 *) (attr + 1));
@@ -458,7 +458,7 @@
const u8 *addr[2];
size_t len[2];
- msg->hdr->length = htons(wpabuf_len(msg->buf));
+ msg->hdr->length = host_to_be16(wpabuf_len(msg->buf));
os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
addr[0] = wpabuf_head(msg->buf);
len[0] = wpabuf_len(msg->buf);
@@ -562,8 +562,8 @@
size_t *nattr_pos;
int nlen = msg->attr_size * 2;
- nattr_pos = os_realloc(msg->attr_pos,
- nlen * sizeof(*msg->attr_pos));
+ nattr_pos = os_realloc_array(msg->attr_pos, nlen,
+ sizeof(*msg->attr_pos));
if (nattr_pos == NULL)
return -1;
@@ -633,7 +633,7 @@
hdr = (struct radius_hdr *) data;
- msg_len = ntohs(hdr->length);
+ msg_len = be_to_host16(hdr->length);
if (msg_len < sizeof(*hdr) || msg_len > len) {
wpa_printf(MSG_INFO, "RADIUS: Invalid message length");
return NULL;
@@ -707,9 +707,9 @@
}
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg)
{
- u8 *eap, *pos;
+ struct wpabuf *eap;
size_t len, i;
struct radius_attr_hdr *attr;
@@ -719,30 +719,27 @@
len = 0;
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
- if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
+ if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+ attr->length > sizeof(struct radius_attr_hdr))
len += attr->length - sizeof(struct radius_attr_hdr);
}
if (len == 0)
return NULL;
- eap = os_malloc(len);
+ eap = wpabuf_alloc(len);
if (eap == NULL)
return NULL;
- pos = eap;
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
- if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
+ if (attr->type == RADIUS_ATTR_EAP_MESSAGE &&
+ attr->length > sizeof(struct radius_attr_hdr)) {
int flen = attr->length - sizeof(*attr);
- os_memcpy(pos, attr + 1, flen);
- pos += flen;
+ wpabuf_put_data(eap, attr + 1, flen);
}
}
- if (eap_len)
- *eap_len = len;
-
return eap;
}
@@ -843,7 +840,7 @@
for (i = 0; i < src->attr_used; i++) {
attr = radius_get_attr_hdr(src, i);
- if (attr->type == type) {
+ if (attr->type == type && attr->length >= sizeof(*attr)) {
if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
attr->length - sizeof(*attr)))
return -1;
@@ -900,7 +897,8 @@
u32 vendor_id;
struct radius_attr_vendor *vhdr;
- if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
+ if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC ||
+ attr->length < sizeof(*attr))
continue;
left = attr->length - sizeof(*attr);
@@ -1273,7 +1271,7 @@
}
}
- if (!attr)
+ if (!attr || attr->length < sizeof(*attr))
return -1;
dlen = attr->length - sizeof(*attr);
@@ -1298,7 +1296,7 @@
}
}
- if (!attr)
+ if (!attr || attr->length < sizeof(*attr))
return -1;
*buf = (u8 *) (attr + 1);
@@ -1349,6 +1347,8 @@
for (i = 0; i < msg->attr_used; i++) {
attr = radius_get_attr_hdr(msg, i);
+ if (attr->length < sizeof(*attr))
+ return -1;
data = (const u8 *) (attr + 1);
dlen = attr->length - sizeof(*attr);
if (attr->length < 3)
@@ -1534,7 +1534,7 @@
if (src->attr == NULL)
return 0;
- dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
+ dst->attr = os_calloc(src->count, sizeof(struct radius_attr_data));
if (dst->attr == NULL)
return -1;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 2d059df..727640b 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -18,7 +18,7 @@
struct radius_hdr {
u8 code;
u8 identifier;
- u16 length; /* including this header */
+ be16 length; /* including this header */
u8 authenticator[16];
/* followed by length-20 octets of attributes */
} STRUCT_PACKED;
@@ -213,7 +213,7 @@
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
size_t data_len);
-u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len);
+struct wpabuf * radius_msg_get_eap(struct radius_msg *msg);
int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
size_t secret_len, struct radius_msg *sent_msg,
int auth);
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 1ee7131..425ad93 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -281,8 +281,8 @@
num = &radius->num_auth_handlers;
}
- newh = os_realloc(*handlers,
- (*num + 1) * sizeof(struct radius_rx_handler));
+ newh = os_realloc_array(*handlers, *num + 1,
+ sizeof(struct radius_rx_handler));
if (newh == NULL)
return -1;
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
index 8ecfffc..bded965 100644
--- a/src/radius/radius_das.c
+++ b/src/radius/radius_das.c
@@ -127,8 +127,11 @@
return NULL;
if (error) {
- radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
- error);
+ if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+ error)) {
+ radius_msg_free(reply);
+ return NULL;
+ }
}
return reply;
@@ -225,7 +228,12 @@
break;
/* Unsupported Service */
- radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
+ if (!radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+ 405)) {
+ radius_msg_free(reply);
+ reply = NULL;
+ break;
+ }
break;
default:
wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 123c59b..5b2d711 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -689,8 +689,7 @@
const char *from_addr, int from_port,
struct radius_session *force_sess)
{
- u8 *eap = NULL;
- size_t eap_len;
+ struct wpabuf *eap = NULL;
int res, state_included = 0;
u8 statebuf[4];
unsigned int state;
@@ -754,7 +753,7 @@
return -1;
}
- eap = radius_msg_get_eap(msg, &eap_len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
from_addr);
@@ -763,7 +762,7 @@
return -1;
}
- RADIUS_DUMP("Received EAP data", eap, eap_len);
+ RADIUS_DUMP("Received EAP data", wpabuf_head(eap), wpabuf_len(eap));
/* FIX: if Code is Request, Success, or Failure, send Access-Reject;
* RFC3579 Sect. 2.6.2.
@@ -773,10 +772,7 @@
* Or is this already done by the EAP state machine? */
wpabuf_free(sess->eap_if->eapRespData);
- sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len);
- if (sess->eap_if->eapRespData == NULL)
- os_free(eap);
- eap = NULL;
+ sess->eap_if->eapRespData = eap;
sess->eap_if->eapResp = TRUE;
eap_server_sm_step(sess->eap);
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index 3d5aac6..f2bac34 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -221,6 +221,9 @@
if (cipher & WPA_CIPHER_CCMP) {
wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
cipher = WPA_CIPHER_CCMP;
+ } else if (cipher & WPA_CIPHER_GCMP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+ cipher = WPA_CIPHER_GCMP;
} else if (cipher & WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
cipher = WPA_CIPHER_TKIP;
@@ -267,10 +270,7 @@
/* Include only the selected cipher in pairwise cipher suite */
WPA_PUT_LE16(pos, 1);
pos += 2;
- if (cipher == WPA_CIPHER_CCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- else if (cipher == WPA_CIPHER_TKIP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
pos += RSN_SELECTOR_LEN;
hdr->len = (pos - peerkey->rsnie_p) - 2;
@@ -344,7 +344,7 @@
msg->type = EAPOL_KEY_TYPE_RSN;
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -352,7 +352,7 @@
key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
WPA_PUT_BE16(msg->key_info, key_info);
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
WPA_PUT_BE16(msg->key_length, 16);
else
WPA_PUT_BE16(msg->key_length, 32);
@@ -403,7 +403,7 @@
msg->type = EAPOL_KEY_TYPE_RSN;
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -412,7 +412,7 @@
WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
WPA_PUT_BE16(msg->key_info, key_info);
- if (peerkey->cipher == WPA_CIPHER_CCMP)
+ if (peerkey->cipher != WPA_CIPHER_TKIP)
WPA_PUT_BE16(msg->key_length, 16);
else
WPA_PUT_BE16(msg->key_length, 32);
@@ -500,6 +500,9 @@
if (cipher & WPA_CIPHER_CCMP) {
wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
peerkey->cipher = WPA_CIPHER_CCMP;
+ } else if (cipher & WPA_CIPHER_GCMP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+ peerkey->cipher = WPA_CIPHER_GCMP;
} else if (cipher & WPA_CIPHER_TKIP) {
wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
peerkey->cipher = WPA_CIPHER_TKIP;
@@ -1016,7 +1019,7 @@
return -1;
}
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+ if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1055,17 +1058,8 @@
count_pos = pos;
pos += 2;
- count = 0;
- if (sm->allowed_pairwise_cipher & WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- pos += RSN_SELECTOR_LEN;
- count++;
- }
- if (sm->allowed_pairwise_cipher & WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- pos += RSN_SELECTOR_LEN;
- count++;
- }
+ count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
+ pos += count * RSN_SELECTOR_LEN;
WPA_PUT_LE16(count_pos, count);
hdr->len = (pos - peerkey->rsnie_i) - 2;
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 2d265d0..9783e7c 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -197,11 +197,25 @@
if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
/* Remove the oldest entry to make room for the new entry */
pos = pmksa->pmksa;
- pmksa->pmksa = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
- "entry (for " MACSTR ") to make room for new one",
- MAC2STR(pos->aa));
- pmksa_cache_free_entry(pmksa, pos, 0);
+
+ if (pos == pmksa->sm->cur_pmksa) {
+ /*
+ * Never remove the current PMKSA cache entry, since
+ * it's in use, and removing it triggers a needless
+ * deauthentication.
+ */
+ pos = pos->next;
+ pmksa->pmksa->next = pos ? pos->next : NULL;
+ } else
+ pmksa->pmksa = pos->next;
+
+ if (pos) {
+ wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
+ "PMKSA cache entry (for " MACSTR ") to "
+ "make room for new one",
+ MAC2STR(pos->aa));
+ pmksa_cache_free_entry(pmksa, pos, 0);
+ }
}
/* Add the new entry; order by expiration time */
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 7159c3a..5cf32df 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -91,7 +91,7 @@
if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
- else if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+ else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -190,14 +190,17 @@
#endif /* CONFIG_IEEE80211R */
}
if (res == 0) {
+ struct rsn_pmksa_cache_entry *sa = NULL;
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
if (sm->proto == WPA_PROTO_RSN &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
- pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len,
- src_addr, sm->own_addr,
- sm->network_ctx, sm->key_mgmt);
+ sa = pmksa_cache_add(sm->pmksa,
+ sm->pmk, pmk_len,
+ src_addr, sm->own_addr,
+ sm->network_ctx,
+ sm->key_mgmt);
}
if (!sm->cur_pmksa && pmkid &&
pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
@@ -207,6 +210,9 @@
"PMKID");
abort_cached = 0;
}
+
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to get master session key from "
@@ -350,7 +356,7 @@
const struct wpa_eapol_key *key,
struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
+ size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
@@ -514,28 +520,23 @@
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: Installing PTK to the driver");
- switch (sm->pairwise_cipher) {
- case WPA_CIPHER_CCMP:
- alg = WPA_ALG_CCMP;
- keylen = 16;
- rsclen = 6;
- break;
- case WPA_CIPHER_TKIP:
- alg = WPA_ALG_TKIP;
- keylen = 32;
- rsclen = 6;
- break;
- case WPA_CIPHER_NONE:
+ if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
"Suite: NONE - do not use pairwise keys");
return 0;
- default:
+ }
+
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported pairwise cipher %d",
sm->pairwise_cipher);
return -1;
}
+ alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+ keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+ rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
+
if (sm->proto == WPA_PROTO_RSN) {
key_rsc = null_rsc;
} else {
@@ -568,55 +569,25 @@
int *key_rsc_len,
enum wpa_alg *alg)
{
- int ret = 0;
+ int klen;
- switch (group_cipher) {
- case WPA_CIPHER_CCMP:
- if (keylen != 16 || maxkeylen < 16) {
- ret = -1;
- break;
- }
- *key_rsc_len = 6;
- *alg = WPA_ALG_CCMP;
- break;
- case WPA_CIPHER_TKIP:
- if (keylen != 32 || maxkeylen < 32) {
- ret = -1;
- break;
- }
- *key_rsc_len = 6;
- *alg = WPA_ALG_TKIP;
- break;
- case WPA_CIPHER_WEP104:
- if (keylen != 13 || maxkeylen < 13) {
- ret = -1;
- break;
- }
- *key_rsc_len = 0;
- *alg = WPA_ALG_WEP;
- break;
- case WPA_CIPHER_WEP40:
- if (keylen != 5 || maxkeylen < 5) {
- ret = -1;
- break;
- }
- *key_rsc_len = 0;
- *alg = WPA_ALG_WEP;
- break;
- default:
+ *alg = wpa_cipher_to_alg(group_cipher);
+ if (*alg == WPA_ALG_NONE) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported Group Cipher %d",
group_cipher);
return -1;
}
+ *key_rsc_len = wpa_cipher_rsc_len(group_cipher);
- if (ret < 0 ) {
+ klen = wpa_cipher_key_len(group_cipher);
+ if (keylen != klen || maxkeylen < klen) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported %s Group Cipher key length %d (%d)",
wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+ return -1;
}
-
- return ret;
+ return 0;
}
@@ -1116,23 +1087,12 @@
}
keylen = WPA_GET_BE16(key->key_length);
- switch (sm->pairwise_cipher) {
- case WPA_CIPHER_CCMP:
- if (keylen != 16) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Invalid CCMP key length %d (src=" MACSTR
- ")", keylen, MAC2STR(sm->bssid));
- goto failed;
- }
- break;
- case WPA_CIPHER_TKIP:
- if (keylen != 32) {
- wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Invalid TKIP key length %d (src=" MACSTR
- ")", keylen, MAC2STR(sm->bssid));
- goto failed;
- }
- break;
+ if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid %s key length %d (src=" MACSTR
+ ")", wpa_cipher_txt(sm->pairwise_cipher), keylen,
+ MAC2STR(sm->bssid));
+ goto failed;
}
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
@@ -1712,6 +1672,13 @@
} else
goto out;
}
+ if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: GCMP is used, but EAPOL-Key "
+ "descriptor version (%d) is not 2", ver);
+ goto out;
+ }
#ifdef CONFIG_PEERKEY
for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
@@ -1846,23 +1813,6 @@
#ifdef CONFIG_CTRL_IFACE
-static int wpa_cipher_bits(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return 128;
- case WPA_CIPHER_TKIP:
- return 256;
- case WPA_CIPHER_WEP104:
- return 104;
- case WPA_CIPHER_WEP40:
- return 40;
- default:
- return 0;
- }
-}
-
-
static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
{
switch (sm->key_mgmt) {
@@ -1894,30 +1844,6 @@
}
-static u32 wpa_cipher_suite(struct wpa_sm *sm, int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
- case WPA_CIPHER_TKIP:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
- case WPA_CIPHER_WEP104:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
- case WPA_CIPHER_WEP40:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
- case WPA_CIPHER_NONE:
- return (sm->proto == WPA_PROTO_RSN ?
- RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
- default:
- return 0;
- }
-}
-
-
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
@@ -1965,7 +1891,7 @@
rsna ? "TRUE" : "FALSE",
rsna ? "TRUE" : "FALSE",
RSN_VERSION,
- wpa_cipher_bits(sm->group_cipher),
+ wpa_cipher_key_len(sm->group_cipher) * 8,
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
@@ -1985,12 +1911,16 @@
"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
"dot11RSNA4WayHandshakeFailures=%u\n",
RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->pairwise_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->group_cipher)),
pmkid_txt,
RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->pairwise_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+ sm->group_cipher)),
sm->dot11RSNA4WayHandshakeFailures);
if (ret >= 0 && (size_t) ret < buflen)
len += ret;
@@ -2659,3 +2589,102 @@
pmksa_cache_flush(sm->pmksa, network_ctx);
#endif /* CONFIG_NO_WPA2 */
}
+
+
+#ifdef CONFIG_IEEE80211V
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
+{
+ struct wpa_gtk_data gd;
+#ifdef CONFIG_IEEE80211W
+ struct wpa_igtk_kde igd;
+ u16 keyidx;
+#endif /* CONFIG_IEEE80211W */
+ u16 keyinfo;
+ u8 keylen; /* plaintext key len */
+ u8 keydatalen;
+ u8 *key_rsc;
+
+ os_memset(&gd, 0, sizeof(gd));
+#ifdef CONFIG_IEEE80211W
+ os_memset(&igd, 0, sizeof(igd));
+#endif /* CONFIG_IEEE80211W */
+
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (gd.alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+ return -1;
+ }
+
+ if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+ key_rsc = buf + 5;
+ keyinfo = WPA_GET_LE16(buf+2);
+ keydatalen = buf[1] - 11 - 8;
+ gd.gtk_len = keylen;
+ if (gd.gtk_len != buf[4]) {
+ wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
+ gd.gtk_len, buf[4]);
+ return -1;
+ }
+ gd.keyidx = keyinfo & 0x03; /* B0 - B1 */
+ gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
+ sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
+
+ if (keydatalen % 8) {
+ wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
+ "%d", keydatalen);
+ return -1;
+ }
+
+ if (aes_unwrap(sm->ptk.kek, keydatalen / 8, buf + 13, gd.gtk))
+ {
+ wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
+ "could not decrypt GTK");
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
+ gd.gtk, gd.gtk_len);
+ if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+ wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
+ "WNM mode");
+ return -1;
+ }
+#ifdef CONFIG_IEEE80211W
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+ if (buf[1] != 2 + 6 + WPA_IGTK_LEN + 8) {
+ wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
+ "%d", buf[1] - 2 - 6 - 8);
+ return -1;
+ }
+ os_memcpy(igd.keyid, buf + 2, 2);
+ os_memcpy(igd.pn, buf + 4, 6);
+
+ keyidx = WPA_GET_LE16(igd.keyid);
+
+ if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, buf + 10,
+ igd.igtk)) {
+ wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
+ "could not decrypr IGTK");
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
+ igd.igtk, WPA_IGTK_LEN);
+ if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+ keyidx, 0, igd.pn, sizeof(igd.pn),
+ igd.igtk, WPA_IGTK_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
+ "WNM mode");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211W */
+ } else {
+ wpa_printf(MSG_DEBUG, "Unknown element id");
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211V */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index a70b57b..1077b5a 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -366,4 +366,8 @@
void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+#ifdef CONFIG_IEEE80211V
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+#endif /* CONFIG_IEEE80211V */
+
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index fec9544..2df060c 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -171,16 +171,16 @@
pos = (u8 *) (rsnie + 1);
/* Group Suite Selector */
- if (sm->group_cipher == WPA_CIPHER_CCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- else if (sm->group_cipher == WPA_CIPHER_TKIP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- else {
+ if (sm->group_cipher != WPA_CIPHER_CCMP &&
+ sm->group_cipher != WPA_CIPHER_GCMP &&
+ sm->group_cipher != WPA_CIPHER_TKIP) {
wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
sm->group_cipher);
os_free(buf);
return NULL;
}
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ sm->group_cipher));
pos += RSN_SELECTOR_LEN;
/* Pairwise Suite Count */
@@ -188,16 +188,14 @@
pos += 2;
/* Pairwise Suite List */
- if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- else if (sm->pairwise_cipher == WPA_CIPHER_TKIP)
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- else {
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
sm->pairwise_cipher);
os_free(buf);
return NULL;
}
+ RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
+ sm->pairwise_cipher));
pos += RSN_SELECTOR_LEN;
/* Authenticated Key Management Suite Count */
@@ -323,21 +321,15 @@
wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
- switch (sm->pairwise_cipher) {
- case WPA_CIPHER_CCMP:
- alg = WPA_ALG_CCMP;
- keylen = 16;
- break;
- case WPA_CIPHER_TKIP:
- alg = WPA_ALG_TKIP;
- keylen = 32;
- break;
- default:
+ if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
sm->pairwise_cipher);
return -1;
}
+ alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+ keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+
if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
@@ -483,7 +475,7 @@
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
+ ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
bssid, sm->pmk_r1_name,
(u8 *) &sm->ptk, ptk_len, ptk_name);
@@ -571,28 +563,10 @@
return -1;
}
- switch (sm->group_cipher) {
- case WPA_CIPHER_CCMP:
- keylen = 16;
- rsc_len = 6;
- alg = WPA_ALG_CCMP;
- break;
- case WPA_CIPHER_TKIP:
- keylen = 32;
- rsc_len = 6;
- alg = WPA_ALG_TKIP;
- break;
- case WPA_CIPHER_WEP104:
- keylen = 13;
- rsc_len = 0;
- alg = WPA_ALG_WEP;
- break;
- case WPA_CIPHER_WEP40:
- keylen = 5;
- rsc_len = 0;
- alg = WPA_ALG_WEP;
- break;
- default:
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (alg == WPA_ALG_NONE) {
wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
sm->group_cipher);
return -1;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 56d564c..6a8f9f1 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -41,6 +41,7 @@
{
u8 *pos;
struct wpa_ie_hdr *hdr;
+ u32 suite;
if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
@@ -52,34 +53,26 @@
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
- if (group_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- } else if (group_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- } else if (group_cipher == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
- } else if (group_cipher == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
+ if (suite == 0) {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
group_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (pairwise_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
- } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
- } else if (pairwise_cipher == WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
+ if (suite == 0 ||
+ (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+ pairwise_cipher != WPA_CIPHER_NONE)) {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
pairwise_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += WPA_SELECTOR_LEN;
*pos++ = 1;
@@ -116,6 +109,7 @@
u8 *pos;
struct rsn_ie_hdr *hdr;
u16 capab;
+ u32 suite;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
@@ -130,34 +124,26 @@
WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
- if (group_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- } else if (group_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- } else if (group_cipher == WPA_CIPHER_WEP104) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
- } else if (group_cipher == WPA_CIPHER_WEP40) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+ if (suite == 0) {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
group_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (pairwise_cipher == WPA_CIPHER_CCMP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
- } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
- } else if (pairwise_cipher == WPA_CIPHER_NONE) {
- RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
- } else {
+ suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+ if (suite == 0 ||
+ (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+ pairwise_cipher != WPA_CIPHER_NONE)) {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
pairwise_cipher);
return -1;
}
+ RSN_SELECTOR_PUT(pos, suite);
pos += RSN_SELECTOR_LEN;
*pos++ = 1;
diff --git a/src/utils/common.c b/src/utils/common.c
index 26fea1b..e636984 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -344,6 +344,135 @@
#endif /* CONFIG_NATIVE_WINDOWS */
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
+{
+ char *end = txt + maxlen;
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (txt + 4 > end)
+ break;
+
+ switch (data[i]) {
+ case '\"':
+ *txt++ = '\\';
+ *txt++ = '\"';
+ break;
+ case '\\':
+ *txt++ = '\\';
+ *txt++ = '\\';
+ break;
+ case '\e':
+ *txt++ = '\\';
+ *txt++ = 'e';
+ break;
+ case '\n':
+ *txt++ = '\\';
+ *txt++ = 'n';
+ break;
+ case '\r':
+ *txt++ = '\\';
+ *txt++ = 'r';
+ break;
+ case '\t':
+ *txt++ = '\\';
+ *txt++ = 't';
+ break;
+ default:
+ if (data[i] >= 32 && data[i] <= 127) {
+ *txt++ = data[i];
+ } else {
+ txt += os_snprintf(txt, end - txt, "\\x%02x",
+ data[i]);
+ }
+ break;
+ }
+ }
+
+ *txt = '\0';
+}
+
+
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
+{
+ const char *pos = str;
+ size_t len = 0;
+ int val;
+
+ while (*pos) {
+ if (len == maxlen)
+ break;
+ switch (*pos) {
+ case '\\':
+ pos++;
+ switch (*pos) {
+ case '\\':
+ buf[len++] = '\\';
+ pos++;
+ break;
+ case '"':
+ buf[len++] = '"';
+ pos++;
+ break;
+ case 'n':
+ buf[len++] = '\n';
+ pos++;
+ break;
+ case 'r':
+ buf[len++] = '\r';
+ pos++;
+ break;
+ case 't':
+ buf[len++] = '\t';
+ pos++;
+ break;
+ case 'e':
+ buf[len++] = '\e';
+ pos++;
+ break;
+ case 'x':
+ pos++;
+ val = hex2byte(pos);
+ if (val < 0) {
+ val = hex2num(*pos);
+ if (val < 0)
+ break;
+ buf[len++] = val;
+ pos++;
+ } else {
+ buf[len++] = val;
+ pos += 2;
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ val = *pos++ - '0';
+ if (*pos >= '0' && *pos <= '7')
+ val = val * 8 + (*pos++ - '0');
+ if (*pos >= '0' && *pos <= '7')
+ val = val * 8 + (*pos++ - '0');
+ buf[len++] = val;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ buf[len++] = *pos++;
+ break;
+ }
+ }
+
+ return len;
+}
+
+
/**
* wpa_ssid_txt - Convert SSID to a printable string
* @ssid: SSID (32-octet string)
@@ -360,19 +489,14 @@
*/
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
{
- static char ssid_txt[33];
- char *pos;
+ static char ssid_txt[32 * 4 + 1];
- if (ssid_len > 32)
- ssid_len = 32;
- os_memcpy(ssid_txt, ssid, ssid_len);
- ssid_txt[ssid_len] = '\0';
- for (pos = ssid_txt; *pos != '\0'; pos++) {
-#ifndef WPA_UNICODE_SSID
- if ((u8) *pos < 32 || (u8) *pos >= 127)
- *pos = '_';
-#endif
+ if (ssid == NULL) {
+ ssid_txt[0] = '\0';
+ return ssid_txt;
}
+
+ printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
return ssid_txt;
}
@@ -381,3 +505,108 @@
{
return foo;
}
+
+
+char * wpa_config_parse_string(const char *value, size_t *len)
+{
+ if (*value == '"') {
+ const char *pos;
+ char *str;
+ value++;
+ pos = os_strrchr(value, '"');
+ if (pos == NULL || pos[1] != '\0')
+ return NULL;
+ *len = pos - value;
+ str = os_malloc(*len + 1);
+ if (str == NULL)
+ return NULL;
+ os_memcpy(str, value, *len);
+ str[*len] = '\0';
+ return str;
+ } else if (*value == 'P' && value[1] == '"') {
+ const char *pos;
+ char *tstr, *str;
+ size_t tlen;
+ value += 2;
+ pos = os_strrchr(value, '"');
+ if (pos == NULL || pos[1] != '\0')
+ return NULL;
+ tlen = pos - value;
+ tstr = os_malloc(tlen + 1);
+ if (tstr == NULL)
+ return NULL;
+ os_memcpy(tstr, value, tlen);
+ tstr[tlen] = '\0';
+
+ str = os_malloc(tlen + 1);
+ if (str == NULL) {
+ os_free(tstr);
+ return NULL;
+ }
+
+ *len = printf_decode((u8 *) str, tlen + 1, tstr);
+ os_free(tstr);
+
+ return str;
+ } else {
+ u8 *str;
+ size_t tlen, hlen = os_strlen(value);
+ if (hlen & 1)
+ return NULL;
+ tlen = hlen / 2;
+ str = os_malloc(tlen + 1);
+ if (str == NULL)
+ return NULL;
+ if (hexstr2bin(value, str, tlen)) {
+ os_free(str);
+ return NULL;
+ }
+ str[tlen] = '\0';
+ *len = tlen;
+ return (char *) str;
+ }
+}
+
+
+int is_hex(const u8 *data, size_t len)
+{
+ size_t i;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] < 32 || data[i] >= 127)
+ return 1;
+ }
+ return 0;
+}
+
+
+size_t merge_byte_arrays(u8 *res, size_t res_len,
+ const u8 *src1, size_t src1_len,
+ const u8 *src2, size_t src2_len)
+{
+ size_t len = 0;
+
+ os_memset(res, 0, res_len);
+
+ if (src1) {
+ if (src1_len >= res_len) {
+ os_memcpy(res, src1, res_len);
+ return res_len;
+ }
+
+ os_memcpy(res, src1, src1_len);
+ len += src1_len;
+ }
+
+ if (src2) {
+ if (len + src2_len >= res_len) {
+ os_memcpy(res + len, src2, res_len - len);
+ return res_len;
+ }
+
+ os_memcpy(res + len, src2, src2_len);
+ len += src2_len;
+ }
+
+ return len;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 7f115ef..5fc916c 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -441,8 +441,17 @@
#define wpa_strdup_tchar(s) strdup((s))
#endif /* CONFIG_NATIVE_WINDOWS */
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
+
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
+char * wpa_config_parse_string(const char *value, size_t *len);
+int is_hex(const u8 *data, size_t len);
+size_t merge_byte_arrays(u8 *res, size_t res_len,
+ const u8 *src1, size_t src1_len,
+ const u8 *src2, size_t src2_len);
+
static inline int is_zero_ether_addr(const u8 *a)
{
return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
diff --git a/src/utils/edit.c b/src/utils/edit.c
index 280d244..b01e08d 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -20,6 +20,7 @@
static int cmdbuf_len = 0;
static char currbuf[CMD_BUF_LEN];
static int currbuf_valid = 0;
+static const char *ps2 = NULL;
#define HISTORY_MAX 100
@@ -47,7 +48,7 @@
{
int i;
putchar('\r');
- for (i = 0; i < cmdbuf_len + 2; i++)
+ for (i = 0; i < cmdbuf_len + 2 + (ps2 ? (int) os_strlen(ps2) : 0); i++)
putchar(' ');
}
@@ -346,7 +347,7 @@
{
if (cmdbuf_len == 0) {
- printf("\n> ");
+ printf("\n%s> ", ps2 ? ps2 : "");
fflush(stdout);
return;
}
@@ -356,7 +357,7 @@
cmdbuf_pos = 0;
cmdbuf_len = 0;
edit_cmd_cb(edit_cb_ctx, cmdbuf);
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
}
@@ -1112,7 +1113,7 @@
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
currbuf[0] = '\0';
dl_list_init(&history_list);
@@ -1132,7 +1133,8 @@
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
- printf("> ");
+ ps2 = ps;
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return 0;
@@ -1161,11 +1163,11 @@
{
char tmp;
cmdbuf[cmdbuf_len] = '\0';
- printf("\r> %s", cmdbuf);
+ printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
if (cmdbuf_pos != cmdbuf_len) {
tmp = cmdbuf[cmdbuf_pos];
cmdbuf[cmdbuf_pos] = '\0';
- printf("\r> %s", cmdbuf);
+ printf("\r%s> %s", ps2 ? ps2 : "", cmdbuf);
cmdbuf[cmdbuf_pos] = tmp;
}
fflush(stdout);
diff --git a/src/utils/edit.h b/src/utils/edit.h
index e8d04e7..ad27f1c 100644
--- a/src/utils/edit.h
+++ b/src/utils/edit.h
@@ -12,7 +12,7 @@
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file);
+ void *ctx, const char *history_file, const char *ps);
void edit_deinit(const char *history_file,
int (*filter_cb)(void *ctx, const char *cmd));
void edit_clear_line(void);
diff --git a/src/utils/edit_readline.c b/src/utils/edit_readline.c
index c9ff0e6..add26fa 100644
--- a/src/utils/edit_readline.c
+++ b/src/utils/edit_readline.c
@@ -112,7 +112,7 @@
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
edit_cb_ctx = ctx;
edit_cmd_cb = cmd_cb;
@@ -127,6 +127,17 @@
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+ if (ps) {
+ size_t blen = os_strlen(ps) + 3;
+ char *ps2 = os_malloc(blen);
+ if (ps2) {
+ os_snprintf(ps2, blen, "%s> ", ps);
+ rl_callback_handler_install(ps2, readline_cmd_handler);
+ os_free(ps2);
+ return 0;
+ }
+ }
+
rl_callback_handler_install("> ", readline_cmd_handler);
return 0;
@@ -136,6 +147,9 @@
void edit_deinit(const char *history_file,
int (*filter_cb)(void *ctx, const char *cmd))
{
+ rl_set_prompt("");
+ rl_replace_line("", 0);
+ rl_redisplay();
rl_callback_handler_remove();
readline_free_completions();
diff --git a/src/utils/edit_simple.c b/src/utils/edit_simple.c
index 0e3637c..a095ea6 100644
--- a/src/utils/edit_simple.c
+++ b/src/utils/edit_simple.c
@@ -16,6 +16,7 @@
#define CMD_BUF_LEN 256
static char cmdbuf[CMD_BUF_LEN];
static int cmdbuf_pos = 0;
+static const char *ps2 = NULL;
static void *edit_cb_ctx;
static void (*edit_cmd_cb)(void *ctx, char *cmd);
@@ -41,7 +42,7 @@
cmdbuf[cmdbuf_pos] = '\0';
cmdbuf_pos = 0;
edit_cmd_cb(edit_cb_ctx, cmdbuf);
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return;
}
@@ -57,14 +58,15 @@
int edit_init(void (*cmd_cb)(void *ctx, char *cmd),
void (*eof_cb)(void *ctx),
char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
- void *ctx, const char *history_file)
+ void *ctx, const char *history_file, const char *ps)
{
edit_cb_ctx = ctx;
edit_cmd_cb = cmd_cb;
edit_eof_cb = eof_cb;
eloop_register_read_sock(STDIN_FILENO, edit_read_char, NULL, NULL);
+ ps2 = ps;
- printf("> ");
+ printf("%s> ", ps2 ? ps2 : "");
fflush(stdout);
return 0;
diff --git a/src/utils/eloop.c b/src/utils/eloop.c
index bb32401..d01ae64 100644
--- a/src/utils/eloop.c
+++ b/src/utils/eloop.c
@@ -153,8 +153,8 @@
#ifdef CONFIG_ELOOP_POLL
if (new_max_sock >= eloop.max_pollfd_map) {
struct pollfd **nmap;
- nmap = os_realloc(eloop.pollfds_map, sizeof(struct pollfd *) *
- (new_max_sock + 50));
+ nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
+ sizeof(struct pollfd *));
if (nmap == NULL)
return -1;
@@ -165,7 +165,8 @@
if (eloop.count + 1 > eloop.max_poll_fds) {
struct pollfd *n;
int nmax = eloop.count + 1 + 50;
- n = os_realloc(eloop.pollfds, sizeof(struct pollfd) * nmax);
+ n = os_realloc_array(eloop.pollfds, nmax,
+ sizeof(struct pollfd));
if (n == NULL)
return -1;
@@ -175,9 +176,8 @@
#endif /* CONFIG_ELOOP_POLL */
eloop_trace_sock_remove_ref(table);
- tmp = (struct eloop_sock *)
- os_realloc(table->table,
- (table->count + 1) * sizeof(struct eloop_sock));
+ tmp = os_realloc_array(table->table, table->count + 1,
+ sizeof(struct eloop_sock));
if (tmp == NULL)
return -1;
@@ -639,10 +639,8 @@
{
struct eloop_signal *tmp;
- tmp = (struct eloop_signal *)
- os_realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
+ tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+ sizeof(struct eloop_signal));
if (tmp == NULL)
return -1;
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
index 1cf5579..1fafeb2 100644
--- a/src/utils/eloop_win.c
+++ b/src/utils/eloop_win.c
@@ -98,8 +98,8 @@
if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
return 0;
- n = os_realloc(eloop.handles,
- eloop.num_handles * 2 * sizeof(eloop.handles[0]));
+ n = os_realloc_array(eloop.handles, eloop.num_handles * 2,
+ sizeof(eloop.handles[0]));
if (n == NULL)
return -1;
eloop.handles = n;
@@ -128,8 +128,8 @@
WSACloseEvent(event);
return -1;
}
- tmp = os_realloc(eloop.readers,
- (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ tmp = os_realloc_array(eloop.readers, eloop.reader_count + 1,
+ sizeof(struct eloop_sock));
if (tmp == NULL) {
WSAEventSelect(sock, event, 0);
WSACloseEvent(event);
@@ -191,8 +191,8 @@
if (eloop_prepare_handles())
return -1;
- tmp = os_realloc(eloop.events,
- (eloop.event_count + 1) * sizeof(struct eloop_event));
+ tmp = os_realloc_array(eloop.events, eloop.event_count + 1,
+ sizeof(struct eloop_event));
if (tmp == NULL)
return -1;
@@ -392,9 +392,8 @@
{
struct eloop_signal *tmp;
- tmp = os_realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
+ tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+ sizeof(struct eloop_signal));
if (tmp == NULL)
return -1;
diff --git a/src/utils/ext_password.c b/src/utils/ext_password.c
new file mode 100644
index 0000000..0613119
--- /dev/null
+++ b/src/utils/ext_password.c
@@ -0,0 +1,116 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, 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"
+
+#ifdef __linux__
+#include <sys/mman.h>
+#endif /* __linux__ */
+
+#include "common.h"
+#include "ext_password_i.h"
+
+
+#ifdef CONFIG_EXT_PASSWORD_TEST
+extern struct ext_password_backend ext_password_test;
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+
+static const struct ext_password_backend *backends[] = {
+#ifdef CONFIG_EXT_PASSWORD_TEST
+ &ext_password_test,
+#endif /* CONFIG_EXT_PASSWORD_TEST */
+ NULL
+};
+
+struct ext_password_data {
+ const struct ext_password_backend *backend;
+ void *priv;
+};
+
+
+struct ext_password_data * ext_password_init(const char *backend,
+ const char *params)
+{
+ struct ext_password_data *data;
+ int i;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ for (i = 0; backends[i]; i++) {
+ if (os_strcmp(backends[i]->name, backend) == 0) {
+ data->backend = backends[i];
+ break;
+ }
+ }
+
+ if (!data->backend) {
+ os_free(data);
+ return NULL;
+ }
+
+ data->priv = data->backend->init(params);
+ if (data->priv == NULL) {
+ os_free(data);
+ return NULL;
+ }
+
+ return data;
+}
+
+
+void ext_password_deinit(struct ext_password_data *data)
+{
+ if (data && data->backend && data->priv)
+ data->backend->deinit(data->priv);
+ os_free(data);
+}
+
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+ const char *name)
+{
+ if (data == NULL)
+ return NULL;
+ return data->backend->get(data->priv, name);
+}
+
+
+struct wpabuf * ext_password_alloc(size_t len)
+{
+ struct wpabuf *buf;
+
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return NULL;
+
+#ifdef __linux__
+ if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s",
+ strerror(errno));
+ }
+#endif /* __linux__ */
+
+ return buf;
+}
+
+
+void ext_password_free(struct wpabuf *pw)
+{
+ if (pw == NULL)
+ return;
+ os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
+#ifdef __linux__
+ if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
+ wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s",
+ strerror(errno));
+ }
+#endif /* __linux__ */
+ wpabuf_free(pw);
+}
diff --git a/src/utils/ext_password.h b/src/utils/ext_password.h
new file mode 100644
index 0000000..e3e46ea
--- /dev/null
+++ b/src/utils/ext_password.h
@@ -0,0 +1,33 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_H
+#define EXT_PASSWORD_H
+
+struct ext_password_data;
+
+#ifdef CONFIG_EXT_PASSWORD
+
+struct ext_password_data * ext_password_init(const char *backend,
+ const char *params);
+void ext_password_deinit(struct ext_password_data *data);
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+ const char *name);
+void ext_password_free(struct wpabuf *pw);
+
+#else /* CONFIG_EXT_PASSWORD */
+
+#define ext_password_init(b, p) ((void *) 1)
+#define ext_password_deinit(d) do { } while (0)
+#define ext_password_get(d, n) (NULL)
+#define ext_password_free(p) do { } while (0)
+
+#endif /* CONFIG_EXT_PASSWORD */
+
+#endif /* EXT_PASSWORD_H */
diff --git a/src/utils/ext_password_i.h b/src/utils/ext_password_i.h
new file mode 100644
index 0000000..043e731
--- /dev/null
+++ b/src/utils/ext_password_i.h
@@ -0,0 +1,23 @@
+/*
+ * External password backend - internal definitions
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_I_H
+#define EXT_PASSWORD_I_H
+
+#include "ext_password.h"
+
+struct ext_password_backend {
+ const char *name;
+ void * (*init)(const char *params);
+ void (*deinit)(void *ctx);
+ struct wpabuf * (*get)(void *ctx, const char *name);
+};
+
+struct wpabuf * ext_password_alloc(size_t len);
+
+#endif /* EXT_PASSWORD_I_H */
diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c
new file mode 100644
index 0000000..3801bb8
--- /dev/null
+++ b/src/utils/ext_password_test.c
@@ -0,0 +1,90 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, 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 "ext_password_i.h"
+
+
+struct ext_password_test_data {
+ char *params;
+};
+
+
+static void * ext_password_test_init(const char *params)
+{
+ struct ext_password_test_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+
+ if (params)
+ data->params = os_strdup(params);
+
+ return data;
+}
+
+
+static void ext_password_test_deinit(void *ctx)
+{
+ struct ext_password_test_data *data = ctx;
+
+ os_free(data->params);
+ os_free(data);
+}
+
+
+static struct wpabuf * ext_password_test_get(void *ctx, const char *name)
+{
+ struct ext_password_test_data *data = ctx;
+ char *pos, *pos2;
+ size_t nlen;
+
+ wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s)", name);
+
+ pos = data->params;
+ if (pos == NULL)
+ return NULL;
+ nlen = os_strlen(name);
+
+ while (pos && *pos) {
+ if (os_strncmp(pos, name, nlen) == 0 && pos[nlen] == '=') {
+ struct wpabuf *buf;
+ pos += nlen + 1;
+ pos2 = pos;
+ while (*pos2 != '|' && *pos2 != '\0')
+ pos2++;
+ buf = ext_password_alloc(pos2 - pos);
+ if (buf == NULL)
+ return NULL;
+ wpabuf_put_data(buf, pos, pos2 - pos);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EXT PW TEST: value",
+ wpabuf_head(buf),
+ wpabuf_len(buf));
+ return buf;
+ }
+
+ pos = os_strchr(pos + 1, '|');
+ if (pos)
+ pos++;
+ }
+
+ wpa_printf(MSG_DEBUG, "EXT PW TEST: get(%s) - not found", name);
+
+ return NULL;
+}
+
+
+const struct ext_password_backend ext_password_test = {
+ .name = "test",
+ .init = ext_password_test_init,
+ .deinit = ext_password_test_deinit,
+ .get = ext_password_test_get,
+};
diff --git a/src/utils/os.h b/src/utils/os.h
index 3058b88..ad20834 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -180,6 +180,25 @@
*/
void * os_zalloc(size_t size);
+/**
+ * os_calloc - Allocate and zero memory for an array
+ * @nmemb: Number of members in the array
+ * @size: Number of bytes in each member
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * This function can be used as a wrapper for os_zalloc(nmemb * size) when an
+ * allocation is used for an array. The main benefit over os_zalloc() is in
+ * having an extra check to catch integer overflows in multiplication.
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+static inline void * os_calloc(size_t nmemb, size_t size)
+{
+ if (size && nmemb > (~(size_t) 0) / size)
+ return NULL;
+ return os_zalloc(nmemb * size);
+}
+
/*
* The following functions are wrapper for standard ANSI C or POSIX functions.
@@ -467,6 +486,14 @@
#endif /* OS_NO_C_LIB_DEFINES */
+static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
+{
+ if (size && nmemb > (~(size_t) 0) / size)
+ return NULL;
+ return os_realloc(ptr, nmemb * size);
+}
+
+
/**
* os_strlcpy - Copy a string with size bound and NUL-termination
* @dest: Destination
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
index b007e66..b257b36 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -68,12 +68,12 @@
if (buf->used + add_len > buf->size) {
unsigned char *nbuf;
- if (buf->ext_data) {
- nbuf = os_realloc(buf->ext_data, buf->used + add_len);
+ if (buf->flags & WPABUF_FLAG_EXT_DATA) {
+ nbuf = os_realloc(buf->buf, buf->used + add_len);
if (nbuf == NULL)
return -1;
os_memset(nbuf + buf->used, 0, add_len);
- buf->ext_data = nbuf;
+ buf->buf = nbuf;
} else {
#ifdef WPA_TRACE
nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
@@ -95,6 +95,7 @@
os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
add_len);
#endif /* WPA_TRACE */
+ buf->buf = (u8 *) (buf + 1);
*_buf = buf;
}
buf->size = buf->used + add_len;
@@ -126,6 +127,7 @@
#endif /* WPA_TRACE */
buf->size = len;
+ buf->buf = (u8 *) (buf + 1);
return buf;
}
@@ -148,7 +150,8 @@
buf->size = len;
buf->used = len;
- buf->ext_data = data;
+ buf->buf = data;
+ buf->flags |= WPABUF_FLAG_EXT_DATA;
return buf;
}
@@ -189,12 +192,14 @@
wpa_trace_show("wpabuf_free magic mismatch");
abort();
}
- os_free(buf->ext_data);
+ if (buf->flags & WPABUF_FLAG_EXT_DATA)
+ os_free(buf->buf);
os_free(trace);
#else /* WPA_TRACE */
if (buf == NULL)
return;
- os_free(buf->ext_data);
+ if (buf->flags & WPABUF_FLAG_EXT_DATA)
+ os_free(buf->buf);
os_free(buf);
#endif /* WPA_TRACE */
}
diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h
index 8c36b40..dbce925 100644
--- a/src/utils/wpabuf.h
+++ b/src/utils/wpabuf.h
@@ -1,6 +1,6 @@
/*
* Dynamic data buffer
- * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,6 +9,9 @@
#ifndef WPABUF_H
#define WPABUF_H
+/* wpabuf::buf is a pointer to external data */
+#define WPABUF_FLAG_EXT_DATA BIT(0)
+
/*
* Internal data structure for wpabuf. Please do not touch this directly from
* elsewhere. This is only defined in header file to allow inline functions
@@ -17,8 +20,8 @@
struct wpabuf {
size_t size; /* total size of the allocated buffer */
size_t used; /* length of data in the buffer */
- u8 *ext_data; /* pointer to external data; NULL if data follows
- * struct wpabuf */
+ u8 *buf; /* pointer to the head of the buffer */
+ unsigned int flags;
/* optionally followed by the allocated buffer */
};
@@ -72,9 +75,7 @@
*/
static inline const void * wpabuf_head(const struct wpabuf *buf)
{
- if (buf->ext_data)
- return buf->ext_data;
- return buf + 1;
+ return buf->buf;
}
static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
@@ -89,9 +90,7 @@
*/
static inline void * wpabuf_mhead(struct wpabuf *buf)
{
- if (buf->ext_data)
- return buf->ext_data;
- return buf + 1;
+ return buf->buf;
}
static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
@@ -150,7 +149,8 @@
static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
{
- buf->ext_data = (u8 *) data;
+ buf->buf = (u8 *) data;
+ buf->flags = WPABUF_FLAG_EXT_DATA;
buf->size = buf->used = len;
}
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 5453962..4c2322d 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -287,7 +287,8 @@
* @msg: WPS IE contents from Beacon or Probe Response frame
* @addr: MAC address to search for
* @ver1_compat: Whether to use version 1 compatibility mode
- * Returns: 1 if address is authorized, 0 if not
+ * Returns: 2 if the specified address is explicit authorized, 1 if address is
+ * authorized (broadcast), 0 if not
*/
int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
int ver1_compat)
@@ -313,8 +314,9 @@
pos = attr.authorized_macs;
for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
- if (os_memcmp(pos, addr, ETH_ALEN) == 0 ||
- os_memcmp(pos, bcast, ETH_ALEN) == 0)
+ if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+ return 2;
+ if (os_memcmp(pos, bcast, ETH_ALEN) == 0)
return 1;
pos += ETH_ALEN;
}
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index da0c101..389aa84 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -1150,7 +1150,7 @@
return WPS_FAILURE;
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -1242,14 +1242,14 @@
}
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -1289,7 +1289,7 @@
}
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
@@ -1300,7 +1300,7 @@
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
attr.enrollee_nonce, WPS_NONCE_LEN);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 44bb006..53684d6 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -2854,7 +2854,7 @@
if (*attr.msg_type != WPS_M1 &&
(attr.registrar_nonce == NULL ||
os_memcmp(wps->nonce_r, attr.registrar_nonce,
- WPS_NONCE_LEN != 0))) {
+ WPS_NONCE_LEN) != 0)) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
@@ -2950,14 +2950,14 @@
#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -3019,14 +3019,14 @@
#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
@@ -3105,14 +3105,14 @@
#endif /* CONFIG_WPS_UPNP */
if (attr.registrar_nonce == NULL ||
- os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+ os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN) != 0)
{
wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
return WPS_FAILURE;
}
if (attr.enrollee_nonce == NULL ||
- os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+ os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
return WPS_FAILURE;
}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 295a897..4f58a92 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -72,6 +72,11 @@
INCLUDES += external/libnl-headers
endif
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.c
OBJS += notify.c
OBJS += bss.c
@@ -184,6 +189,11 @@
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_IEEE80211V
+L_CFLAGS += -DCONFIG_IEEE80211V
+OBJS += wnm_sta.c
+endif
+
ifdef CONFIG_TDLS
L_CFLAGS += -DCONFIG_TDLS
OBJS += src/rsn_supp/tdls.c
@@ -244,6 +254,17 @@
endif
endif
+ifdef CONFIG_WIFI_DISPLAY
+L_CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.c
+endif
+
+ifdef CONFIG_HS20
+OBJS += hs20_supplicant.c
+L_CFLAGS += -DCONFIG_HS20
+CONFIG_INTERWORKING=y
+endif
+
ifdef CONFIG_INTERWORKING
OBJS += interworking.c
L_CFLAGS += -DCONFIG_INTERWORKING
@@ -734,6 +755,10 @@
L_CFLAGS += -DCONFIG_IEEE80211N
endif
+ifdef CONFIG_WNM
+L_CFLAGS += -DCONFIG_WNM
+endif
+
ifdef NEED_AP_MLME
OBJS += src/ap/wmm.c
OBJS += src/ap/ap_list.c
@@ -746,6 +771,12 @@
OBJS += src/ap/wps_hostapd.c
OBJS += src/eap_server/eap_server_wsc.c
endif
+ifdef CONFIG_INTERWORKING
+OBJS += src/ap/gas_serv.c
+endif
+ifdef CONFIG_HS20
+OBJS += src/ap/hs20.c
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -844,8 +875,10 @@
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += src/eap_peer/eap_tls_common.c
OBJS_h += src/eap_server/eap_server_tls_common.c
+ifndef CONFIG_FIPS
NEED_TLS_PRF=y
endif
+endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
@@ -855,6 +888,11 @@
L_CFLAGS += -DCONFIG_TLSV11
endif
+ifdef CONFIG_TLSV12
+L_CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
ifeq ($(CONFIG_TLS), openssl)
ifdef TLS_FUNCS
L_CFLAGS += -DEAP_TLS_OPENSSL
@@ -939,6 +977,9 @@
NEED_SHA256=y
NEED_BASE64=y
NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
NEED_MODEXP=y
NEED_CIPHER=y
L_CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -1044,8 +1085,12 @@
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += src/crypto/aes-omac1.c
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += src/crypto/aes-wrap.c
@@ -1065,7 +1110,10 @@
SHA1OBJS =
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += src/crypto/sha1-internal.c
ifdef NEED_FIPS186_2_PRF
@@ -1075,8 +1123,10 @@
ifdef CONFIG_NO_WPA_PASSPHRASE
L_CFLAGS += -DCONFIG_NO_PBKDF2
else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += src/crypto/sha1-pbkdf2.c
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += src/crypto/sha1-tprf.c
endif
@@ -1085,14 +1135,14 @@
endif
endif
-MD5OBJS = src/crypto/md5.c
+MD5OBJS =
+ifndef CONFIG_FIPS
+MD5OBJS += src/crypto/md5.c
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += src/crypto/md5-internal.c
endif
-ifdef CONFIG_FIPS
-MD5OBJS += src/crypto/md5-non-fips.c
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1119,10 +1169,16 @@
SHA256OBJS = # none by default
ifdef NEED_SHA256
L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += src/crypto/sha256.c
+endif
+SHA256OBJS += src/crypto/sha256-prf.c
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += src/crypto/sha256-internal.c
endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += src/crypto/sha256-tlsprf.c
+endif
OBJS += $(SHA256OBJS)
endif
@@ -1162,6 +1218,11 @@
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
L_CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+L_CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.c ctrl_iface_$(CONFIG_CTRL_IFACE).c
endif
@@ -1282,6 +1343,10 @@
endif
endif
+ifdef CONFIG_DEBUG_LINUX_TRACING
+L_CFLAGS += -DCONFIG_DEBUG_LINUX_TRACING
+endif
+
ifdef CONFIG_DEBUG_FILE
L_CFLAGS += -DCONFIG_DEBUG_FILE
endif
@@ -1297,6 +1362,7 @@
OBJS += $(SHA1OBJS) $(DESOBJS)
OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
ifdef CONFIG_BGSCAN_SIMPLE
L_CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1332,8 +1398,19 @@
OBJS += autoscan.c
endif
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += src/utils/ext_password_test.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += src/utils/ext_password.c
+L_CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
ifdef NEED_GAS
-OBJS += ../src/common/gas.c
+OBJS += src/common/gas.c
OBJS += gas_query.c
L_CFLAGS += -DCONFIG_GAS
NEED_OFFCHANNEL=y
@@ -1371,6 +1448,9 @@
OBJS_priv += src/utils/wpa_debug.c
OBJS_priv += src/utils/wpabuf.c
OBJS_priv += wpa_priv.c
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += src/common/ieee802_11_common.c
+endif
ifdef CONFIG_DRIVER_TEST
OBJS_priv += $(SHA1OBJS)
OBJS_priv += $(MD5OBJS)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 6756e54..227fb4f 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -55,6 +55,11 @@
install: $(addprefix $(DESTDIR)$(BINDIR)/,$(BINALL))
$(MAKE) -C ../src install
+ifdef CONFIG_FIPS
+CONFIG_NO_RANDOM_POOL=
+CONFIG_OPENSSL_CMAC=y
+endif
+
OBJS = config.o
OBJS += notify.o
OBJS += bss.o
@@ -167,6 +172,11 @@
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_IEEE80211V
+CFLAGS += -DCONFIG_IEEE80211V
+OBJS += wnm_sta.o
+endif
+
ifdef CONFIG_TDLS
CFLAGS += -DCONFIG_TDLS
OBJS += ../src/rsn_supp/tdls.o
@@ -227,6 +237,11 @@
endif
endif
+ifdef CONFIG_WIFI_DISPLAY
+CFLAGS += -DCONFIG_WIFI_DISPLAY
+OBJS += wifi_display.o
+endif
+
ifdef CONFIG_HS20
OBJS += hs20_supplicant.o
CFLAGS += -DCONFIG_HS20
@@ -296,6 +311,17 @@
CONFIG_IEEE8021X_EAPOL=y
endif
+ifdef CONFIG_EAP_UNAUTH_TLS
+# EAP-UNAUTH-TLS
+CFLAGS += -DEAP_UNAUTH_TLS
+ifndef CONFIG_EAP_UNAUTH_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+OBJS_h += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
ifeq ($(CONFIG_EAP_PEAP), dyn)
@@ -741,6 +767,9 @@
ifdef CONFIG_INTERWORKING
OBJS += ../src/ap/gas_serv.o
endif
+ifdef CONFIG_HS20
+OBJS += ../src/ap/hs20.o
+endif
endif
ifdef NEED_RSN_AUTHENTICATOR
@@ -839,8 +868,10 @@
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
OBJS += ../src/eap_peer/eap_tls_common.o
OBJS_h += ../src/eap_server/eap_server_tls_common.o
+ifndef CONFIG_FIPS
NEED_TLS_PRF=y
endif
+endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
@@ -868,6 +899,10 @@
endif
LIBS += -lcrypto
LIBS_p += -lcrypto
+ifdef CONFIG_TLS_ADD_DL
+LIBS += -ldl
+LIBS_p += -ldl
+endif
endif
ifeq ($(CONFIG_TLS), gnutls)
@@ -1047,8 +1082,12 @@
endif
ifdef NEED_AES_OMAC1
NEED_AES_ENC=y
+ifdef CONFIG_OPENSSL_CMAC
+CFLAGS += -DCONFIG_OPENSSL_CMAC
+else
AESOBJS += ../src/crypto/aes-omac1.o
endif
+endif
ifdef NEED_AES_WRAP
NEED_AES_ENC=y
AESOBJS += ../src/crypto/aes-wrap.o
@@ -1067,7 +1106,10 @@
endif
ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
ifdef CONFIG_INTERNAL_SHA1
SHA1OBJS += ../src/crypto/sha1-internal.o
ifdef NEED_FIPS186_2_PRF
@@ -1077,8 +1119,10 @@
ifdef CONFIG_NO_WPA_PASSPHRASE
CFLAGS += -DCONFIG_NO_PBKDF2
else
+ifneq ($(CONFIG_TLS), openssl)
SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
endif
+endif
ifdef NEED_T_PRF
SHA1OBJS += ../src/crypto/sha1-tprf.o
endif
@@ -1087,14 +1131,13 @@
endif
endif
-MD5OBJS = ../src/crypto/md5.o
+ifndef CONFIG_FIPS
+MD5OBJS += ../src/crypto/md5.o
+endif
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
MD5OBJS += ../src/crypto/md5-internal.o
endif
-ifdef CONFIG_FIPS
-MD5OBJS += ../src/crypto/md5-non-fips.o
-endif
OBJS += $(MD5OBJS)
OBJS_p += $(MD5OBJS)
endif
@@ -1121,7 +1164,10 @@
SHA256OBJS = # none by default
ifdef NEED_SHA256
CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
SHA256OBJS += ../src/crypto/sha256.o
+endif
+SHA256OBJS += ../src/crypto/sha256-prf.o
ifdef CONFIG_INTERNAL_SHA256
SHA256OBJS += ../src/crypto/sha256-internal.o
endif
@@ -1167,6 +1213,11 @@
ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
endif
+ifeq ($(CONFIG_CTRL_IFACE), udp-remote)
+CONFIG_CTRL_IFACE=udp
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE
+endif
OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
endif
@@ -1297,6 +1348,9 @@
ifdef CONFIG_FIPS
CFLAGS += -DCONFIG_FIPS
+ifneq ($(CONFIG_TLS), openssl)
+$(error CONFIG_FIPS=y requires CONFIG_TLS=openssl)
+endif
endif
OBJS += $(SHA1OBJS) $(DESOBJS)
@@ -1338,6 +1392,17 @@
OBJS += autoscan.o
endif
+ifdef CONFIG_EXT_PASSWORD_TEST
+OBJS += ../src/utils/ext_password_test.o
+CFLAGS += -DCONFIG_EXT_PASSWORD_TEST
+NEED_EXT_PASSWORD=y
+endif
+
+ifdef NEED_EXT_PASSWORD
+OBJS += ../src/utils/ext_password.o
+CFLAGS += -DCONFIG_EXT_PASSWORD
+endif
+
ifdef NEED_GAS
OBJS += ../src/common/gas.o
OBJS += gas_query.o
@@ -1559,6 +1624,11 @@
tests: test-eap_sim_common
+FIPSDIR=/usr/local/ssl/fips-2.0
+FIPSLD=$(FIPSDIR)/bin/fipsld
+fips:
+ $(MAKE) CC=$(FIPSLD) FIPSLD_CC="$(CC)"
+
clean:
$(MAKE) -C ../src clean
$(MAKE) -C dbus clean
diff --git a/wpa_supplicant/README-HS20 b/wpa_supplicant/README-HS20
new file mode 100644
index 0000000..feb9049
--- /dev/null
+++ b/wpa_supplicant/README-HS20
@@ -0,0 +1,470 @@
+wpa_supplicant and Hotspot 2.0
+==============================
+
+This document describe how the IEEE 802.11u Interworking and Wi-Fi
+Hotspot 2.0 (Release 1) implementation in wpa_supplicant can be
+configured and how an external component on the client e.g., management
+GUI or Wi-Fi framework) is used to manage this functionality.
+
+
+Introduction to Wi-Fi Hotspot 2.0
+---------------------------------
+
+Hotspot 2.0 is the name of the Wi-Fi Alliance specification that is used
+in the Wi-Fi CERTIFIED Passpoint<TM> program. More information about
+this is available in this white paper:
+
+http://www.wi-fi.org/knowledge-center/white-papers/wi-fi-certified-passpoint%E2%84%A2-new-program-wi-fi-alliance%C2%AE-enable-seamless
+
+The Hotspot 2.0 specification is also available from WFA:
+https://www.wi-fi.org/knowledge-center/published-specifications
+
+The core Interworking functionality (network selection, GAS/ANQP) were
+standardized in IEEE Std 802.11u-2011 which is now part of the IEEE Std
+802.11-2012.
+
+
+wpa_supplicant network selection
+--------------------------------
+
+Interworking support added option for configuring credentials that can
+work with multiple networks as an alternative to configuration of
+network blocks (e.g., per-SSID parameters). When requested to perform
+network selection, wpa_supplicant picks the highest priority enabled
+network block or credential. If a credential is picked (based on ANQP
+information from APs), a temporary network block is created
+automatically for the matching network. This temporary network block is
+used similarly to the network blocks that can be configured by the user,
+but it is not stored into the configuration file and is meant to be used
+only for temporary period of time since a new one can be created
+whenever needed based on ANQP information and the credential.
+
+By default, wpa_supplicant is not using automatic network selection
+unless requested explicitly with the interworking_select command. This
+can be changed with the auto_interworking=1 parameter to perform network
+selection automatically whenever trying to find a network for connection
+and none of the enabled network blocks match with the scan results. This
+case works similarly to "interworking_select auto", i.e., wpa_supplicant
+will internally determine which network or credential is going to be
+used based on configured priorities, scan results, and ANQP information.
+
+
+wpa_supplicant configuration
+----------------------------
+
+Interworking and Hotspot 2.0 functionality are optional components that
+need to be enabled in the wpa_supplicant build configuration
+(.config). This is done by adding following parameters into that file:
+
+CONFIG_INTERWORKING=y
+CONFIG_HS20=y
+
+It should be noted that this functionality requires a driver that
+supports GAS/ANQP operations. This uses the same design as P2P, i.e.,
+Action frame processing and building in user space within
+wpa_supplicant. The Linux nl80211 driver interface provides the needed
+functionality for this.
+
+
+There are number of run-time configuration parameters (e.g., in
+wpa_supplicant.conf when using the configuration file) that can be used
+to control Hotspot 2.0 operations.
+
+# Enable Interworking
+interworking=1
+
+# Enable Hotspot 2.0
+hs20=1
+
+# Parameters for controlling scanning
+
+# Homogenous ESS identifier
+# If this is set, scans will be used to request response only from BSSes
+# belonging to the specified Homogeneous ESS. This is used only if interworking
+# is enabled.
+#hessid=00:11:22:33:44:55
+
+# Access Network Type
+# When Interworking is enabled, scans can be limited to APs that advertise the
+# specified Access Network Type (0..15; with 15 indicating wildcard match).
+# This value controls the Access Network Type value in Probe Request frames.
+#access_network_type=15
+
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
+
+
+Credentials can be pre-configured for automatic network selection:
+
+# credential block
+#
+# Each credential used for automatic network selection is configured as a set
+# of parameters that are compared to the information advertised by the APs when
+# interworking_select and interworking_connect commands are used.
+#
+# credential fields:
+#
+# priority: Priority group
+# By default, all networks and credentials get the same priority group
+# (0). This field can be used to give higher priority for credentials
+# (and similarly in struct wpa_ssid for network blocks) to change the
+# Interworking automatic networking selection behavior. The matching
+# network (based on either an enabled network block or a credential)
+# with the highest priority value will be selected.
+#
+# pcsc: Use PC/SC and SIM/USIM card
+#
+# realm: Home Realm for Interworking
+#
+# username: Username for Interworking network selection
+#
+# password: Password for Interworking network selection
+#
+# ca_cert: CA certificate for Interworking network selection
+#
+# client_cert: File path to client certificate file (PEM/DER)
+# This field is used with Interworking networking selection for a case
+# where client certificate/private key is used for authentication
+# (EAP-TLS). Full path to the file should be used since working
+# directory may change when wpa_supplicant is run in the background.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key: File path to client private key file (PEM/DER/PFX)
+# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+# commented out. Both the private key and certificate will be read
+# from the PKCS#12 file in this case. Full path to the file should be
+# used since working directory may change when wpa_supplicant is run
+# in the background.
+#
+# Windows certificate store can be used by leaving client_cert out and
+# configuring private_key in one of the following formats:
+#
+# cert://substring_to_match
+#
+# hash://certificate_thumbprint_in_hex
+#
+# For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+#
+# Note that when running wpa_supplicant as an application, the user
+# certificate store (My user account) is used, whereas computer store
+# (Computer account) is used when running wpasvc as a service.
+#
+# Alternatively, a named configuration blob can be used by setting
+# this to blob://blob_name.
+#
+# private_key_passwd: Password for private key file
+#
+# imsi: IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+#
+# milenage: Milenage parameters for SIM/USIM simulator in <Ki>:<OPc>:<SQN>
+# format
+#
+# domain: Home service provider FQDN
+# This is used to compare against the Domain Name List to figure out
+# whether the AP is operated by the Home SP.
+#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# for example:
+#
+#cred={
+# realm="example.com"
+# username="user@example.com"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+#}
+#
+#cred={
+# imsi="310026-000000000"
+# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
+#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
+
+
+Control interface
+-----------------
+
+wpa_supplicant provides a control interface that can be used from
+external programs to manage various operations. The included command
+line tool, wpa_cli, can be used for manual testing with this interface.
+
+Following wpa_cli interactive mode commands show some examples of manual
+operations related to Hotspot 2.0:
+
+Remove configured networks and credentials:
+
+> remove_network all
+OK
+> remove_cred all
+OK
+
+
+Add a username/password credential:
+
+> add_cred
+0
+> set_cred 0 realm "mail.example.com"
+OK
+> set_cred 0 username "username"
+OK
+> set_cred 0 password "password"
+OK
+> set_cred 0 priority 1
+OK
+
+Add a SIM credential using a simulated SIM/USIM card for testing:
+
+> add_cred
+1
+> set_cred 1 imsi "23456-0000000000"
+OK
+> set_cred 1 milenage "90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82581:000000000123"
+OK
+> set_cred 1 priority 1
+OK
+
+Note: the return value of add_cred is used as the first argument to
+the following set_cred commands.
+
+
+Add a WPA2-Enterprise network:
+
+> add_network
+0
+> set_network 0 key_mgmt WPA-EAP
+OK
+> set_network 0 ssid "enterprise"
+OK
+> set_network 0 eap TTLS
+OK
+> set_network 0 anonymous_identity "anonymous"
+OK
+> set_network 0 identity "user"
+OK
+> set_network 0 password "password"
+OK
+> set_network 0 priority 0
+OK
+> enable_network 0 no-connect
+OK
+
+
+Add an open network:
+
+> add_network
+3
+> set_network 3 key_mgmt NONE
+OK
+> set_network 3 ssid "coffee-shop"
+OK
+> select_network 3
+OK
+
+Note: the return value of add_network is used as the first argument to
+the following set_network commands.
+
+The preferred credentials/networks can be indicated with the priority
+parameter (1 is higher priority than 0).
+
+
+Interworking network selection can be started with interworking_select
+command. This instructs wpa_supplicant to run a network scan and iterate
+through the discovered APs to request ANQP information from the APs that
+advertise support for Interworking/Hotspot 2.0:
+
+> interworking_select
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+
+
+INTERWORKING-AP event messages indicate the APs that support network
+selection and for which there is a matching
+credential. interworking_connect command can be used to select a network
+to connect with:
+
+
+> interworking_connect 02:00:00:00:01:00
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (auth) [id=0 id_str=]
+
+
+wpa_supplicant creates a temporary network block for the selected
+network based on the configured credential and ANQP information from the
+AP:
+
+> list_networks
+network id / ssid / bssid / flags
+0 Example Network any [CURRENT]
+> get_network 0 key_mgmt
+WPA-EAP
+> get_network 0 eap
+TTLS
+
+
+Alternatively to using an external program to select the network,
+"interworking_select auto" command can be used to request wpa_supplicant
+to select which network to use based on configured priorities:
+
+
+> remove_network all
+OK
+<3>CTRL-EVENT-DISCONNECTED bssid=02:00:00:00:01:00 reason=1 locally_generated=1
+> interworking_select auto
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
+<3>INTERWORKING-AP 02:00:00:00:01:00 type=unknown
+<3>CTRL-EVENT-SCAN-RESULTS
+<3>SME: Trying to authenticate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Trying to associate with 02:00:00:00:01:00 (SSID='Example Network' freq=2412 MHz)
+<3>Associated with 02:00:00:00:01:00
+<3>CTRL-EVENT-EAP-STARTED EAP authentication started
+<3>CTRL-EVENT-EAP-PROPOSED-METHOD vendor=0 method=21
+<3>CTRL-EVENT-EAP-METHOD EAP vendor 0 method 21 (TTLS) selected
+<3>CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
+<3>WPA: Key negotiation completed with 02:00:00:00:01:00 [PTK=CCMP GTK=CCMP]
+<3>CTRL-EVENT-CONNECTED - Connection to 02:00:00:00:01:00 completed (reauth) [id=0 id_str=]
+
+
+The connection status can be shown with the status command:
+
+> status
+bssid=02:00:00:00:01:00
+ssid=Example Network
+id=0
+mode=station
+pairwise_cipher=CCMP <--- link layer security indication
+group_cipher=CCMP
+key_mgmt=WPA2/IEEE 802.1X/EAP
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+hs20=1 <--- HS 2.0 indication
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+selectedMethod=21 (EAP-TTLS)
+EAP TLS cipher=AES-128-SHA
+EAP-TTLSv0 Phase2 method=PAP
+
+
+> status
+bssid=02:00:00:00:02:00
+ssid=coffee-shop
+id=3
+mode=station
+pairwise_cipher=NONE
+group_cipher=NONE
+key_mgmt=NONE
+wpa_state=COMPLETED
+p2p_device_address=02:00:00:00:00:00
+address=02:00:00:00:00:00
+
+
+Note: The Hotspot 2.0 indication is shown as "hs20=1" in the status
+command output. Link layer security is indicated with the
+pairwise_cipher (CCMP = secure, NONE = no encryption used).
+
+
+Also the scan results include the Hotspot 2.0 indication:
+
+> scan_results
+bssid / frequency / signal level / flags / ssid
+02:00:00:00:01:00 2412 -30 [WPA2-EAP-CCMP][ESS][HS20] Example Network
+
+
+ANQP information for the BSS can be fetched using the BSS command:
+
+> bss 02:00:00:00:01:00
+id=1
+bssid=02:00:00:00:01:00
+freq=2412
+beacon_int=100
+capabilities=0x0411
+qual=0
+noise=-92
+level=-30
+tsf=1345573286517276
+age=105
+ie=000f4578616d706c65204e6574776f726b010882848b960c1218240301012a010432043048606c30140100000fac040100000fac040100000fac0100007f04000000806b091e07010203040506076c027f006f1001531122331020304050010203040506dd05506f9a1000
+flags=[WPA2-EAP-CCMP][ESS][HS20]
+ssid=Example Network
+anqp_roaming_consortium=031122330510203040500601020304050603fedcba
+
+
+ANQP queries can also be requested with the anqp_get and hs20_anqp_get
+commands:
+
+> anqp_get 02:00:00:00:01:00 261
+OK
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+> hs20_anqp_get 02:00:00:00:01:00 2
+OK
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+
+In addition, fetch_anqp command can be used to request similar set of
+ANQP queries to be done as is run as part of interworking_select:
+
+> scan
+OK
+<3>CTRL-EVENT-SCAN-RESULTS
+> fetch_anqp
+OK
+<3>Starting ANQP fetch for 02:00:00:00:01:00
+<3>RX-ANQP 02:00:00:00:01:00 ANQP Capability list
+<3>RX-ANQP 02:00:00:00:01:00 Roaming Consortium list
+<3>RX-HS20-ANQP 02:00:00:00:01:00 HS Capability List
+<3>ANQP fetch completed
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index bb4c2ad..4abc2f2 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -71,7 +71,8 @@
Device Discovery
-p2p_find [timeout in seconds] [type=<social|progressive>]
+p2p_find [timeout in seconds] [type=<social|progressive>] \
+ [dev_id=<addr>] [delay=<search delay in ms>]
The default behavior is to run a single full scan in the beginning and
then scan only social channels. type=social will scan only social
@@ -81,6 +82,11 @@
will help in finding new groups or groups missed during the initial
full scan.
+The optional dev_id option can be used to specify a single P2P peer to
+search for. The optional delay parameter can be used to request an extra
+delay to be used between search iterations (e.g., to free up radio
+resources for concurrent operations).
+
p2p_listen [timeout in seconds]
Start Listen-only state (become discoverable without searching for
@@ -119,7 +125,7 @@
p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
[persistent|persistent=<network id>] [join|auth]
- [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [provdisc]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -160,7 +166,7 @@
P2P implementations that require this to allow the user to accept the
connection.
-p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -250,6 +256,14 @@
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 uuid:6859dede-8574-59ab-9332-123456789012
p2p_serv_disc_req 00:00:00:00:00:00 upnp 10 urn:schemas-upnp-org:device:InternetGatewayDevice:1
+# Wi-Fi Display examples
+# format: wifi-display <list of roles> <list of subelements>
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source] 2,3,4,5
+p2p_serv_disc_req 02:01:02:03:04:05 wifi-display [pri-sink] 3
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [sec-source] 2
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source+sink] 2,3,4,5
+p2p_serv_disc_req 00:00:00:00:00:00 wifi-display [source][pri-sink] 2,3,4,5
+
p2p_serv_disc_cancel_req <query identifier>
Cancel a pending P2P service discovery request. This command takes a
@@ -332,7 +346,7 @@
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
persistent group (e.g., persistent=4). If the peer device is the GO of
@@ -340,7 +354,8 @@
used to specify which device to invite. go_dev_addr parameter can be
used to override the GO device address for Invitation Request should
it be not known for some reason (this should not be needed in most
-cases).
+cases). When reinvoking a persistent group, the GO device can specify
+the frequency for the group with the freq parameter.
Group Operations
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index fc0614d..d71d1d3 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -495,3 +495,6 @@
# Enable P2P
CONFIG_P2P=y
CONFIG_AP=y
+
+#Enable Wifi Display
+CONFIG_WIFI_DISPLAY=y
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index f9e0045..3798f5a 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -99,6 +99,18 @@
if (!no_ht && mode && mode->ht_capab) {
conf->ieee80211n = 1;
+#ifdef CONFIG_P2P
+ if (conf->hw_mode == HOSTAPD_MODE_IEEE80211A &&
+ (mode->ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ ssid->ht40)
+ conf->secondary_channel =
+ wpas_p2p_get_ht40_mode(wpa_s, mode,
+ conf->channel);
+ if (conf->secondary_channel)
+ conf->ht_capab |=
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+#endif /* CONFIG_P2P */
/*
* white-list capabilities that won't cause issues
@@ -150,7 +162,6 @@
return -1;
}
os_memcpy(bss->ssid.ssid, ssid->ssid, ssid->ssid_len);
- bss->ssid.ssid[ssid->ssid_len] = '\0';
bss->ssid.ssid_len = ssid->ssid_len;
bss->ssid.ssid_set = 1;
@@ -207,6 +218,9 @@
}
if (pairwise & WPA_CIPHER_TKIP)
bss->wpa_group = WPA_CIPHER_TKIP;
+ else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+ WPA_CIPHER_GCMP)
+ bss->wpa_group = WPA_CIPHER_GCMP;
else
bss->wpa_group = WPA_CIPHER_CCMP;
@@ -450,6 +464,8 @@
if (ssid->pairwise_cipher & WPA_CIPHER_CCMP)
wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
+ else if (ssid->pairwise_cipher & WPA_CIPHER_GCMP)
+ wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
else if (ssid->pairwise_cipher & WPA_CIPHER_TKIP)
wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
else if (ssid->pairwise_cipher & WPA_CIPHER_NONE)
@@ -491,6 +507,10 @@
return -1;
}
+ os_memcpy(wpa_s->ap_iface->conf->wmm_ac_params,
+ wpa_s->conf->wmm_ac_params,
+ sizeof(wpa_s->conf->wmm_ac_params));
+
if (params.uapsd > 0) {
conf->bss->wmm_enabled = 1;
conf->bss->wmm_uapsd = 1;
@@ -511,7 +531,7 @@
#endif /* CONFIG_P2P */
hapd_iface->num_bss = conf->num_bss;
- hapd_iface->bss = os_zalloc(conf->num_bss *
+ hapd_iface->bss = os_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL) {
wpa_supplicant_ap_deinit(wpa_s);
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index ed4d879..adf82d8 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -75,7 +75,7 @@
if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
return;
- n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN);
+ n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
if (n == NULL)
return;
@@ -219,7 +219,7 @@
dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
if (in_array(freqs, bss->freq))
continue;
- n = os_realloc(freqs, (*count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, *count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
@@ -248,7 +248,7 @@
wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
"%u", data->supp_freqs[idx]);
data->probe_idx = idx;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
@@ -360,7 +360,7 @@
for (j = 0; j < modes[i].num_channels; j++) {
if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
continue;
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 580a82a..d326bef 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -35,6 +35,64 @@
#define WPA_BSS_IES_CHANGED_FLAG BIT(8)
+static void wpa_bss_set_hessid(struct wpa_bss *bss)
+{
+#ifdef CONFIG_INTERWORKING
+ const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
+ if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
+ os_memset(bss->hessid, 0, ETH_ALEN);
+ return;
+ }
+ if (ie[1] == 7)
+ os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
+ else
+ os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+ struct wpa_bss_anqp *anqp;
+ anqp = os_zalloc(sizeof(*anqp));
+ if (anqp == NULL)
+ return NULL;
+ anqp->users = 1;
+ return anqp;
+}
+
+
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+ if (anqp == NULL)
+ return;
+
+ anqp->users--;
+ if (anqp->users > 0) {
+ /* Another BSS entry holds a pointer to this ANQP info */
+ return;
+ }
+
+#ifdef CONFIG_INTERWORKING
+ wpabuf_free(anqp->venue_name);
+ wpabuf_free(anqp->network_auth_type);
+ wpabuf_free(anqp->roaming_consortium);
+ wpabuf_free(anqp->ip_addr_type_availability);
+ wpabuf_free(anqp->nai_realm);
+ wpabuf_free(anqp->anqp_3gpp);
+ wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ wpabuf_free(anqp->hs20_wan_metrics);
+ wpabuf_free(anqp->hs20_connection_capability);
+ wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+ os_free(anqp);
+}
+
+
static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
const char *reason)
{
@@ -45,21 +103,7 @@
" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
-#ifdef CONFIG_INTERWORKING
- wpabuf_free(bss->anqp_venue_name);
- wpabuf_free(bss->anqp_network_auth_type);
- wpabuf_free(bss->anqp_roaming_consortium);
- wpabuf_free(bss->anqp_ip_addr_type_availability);
- wpabuf_free(bss->anqp_nai_realm);
- wpabuf_free(bss->anqp_3gpp);
- wpabuf_free(bss->anqp_domain_name);
-#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_HS20
- wpabuf_free(bss->hs20_operator_friendly_name);
- wpabuf_free(bss->hs20_wan_metrics);
- wpabuf_free(bss->hs20_connection_capability);
- wpabuf_free(bss->hs20_operating_class);
-#endif /* CONFIG_HS20 */
+ wpa_bss_anqp_free(bss->anqp);
os_free(bss);
}
@@ -186,6 +230,7 @@
bss->ie_len = res->ie_len;
bss->beacon_ie_len = res->beacon_ie_len;
os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
@@ -365,6 +410,8 @@
}
dl_list_add(prev, &bss->list_id);
}
+ if (changes & WPA_BSS_IES_CHANGED_FLAG)
+ wpa_bss_set_hessid(bss);
dl_list_add_tail(&wpa_s->bss, &bss->list);
notify_bss_changes(wpa_s, changes, bss);
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 65e962b..8a307cc 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -19,6 +19,25 @@
#define WPA_BSS_ASSOCIATED BIT(5)
#define WPA_BSS_ANQP_FETCH_TRIED BIT(6)
+struct wpa_bss_anqp {
+ unsigned int users;
+#ifdef CONFIG_INTERWORKING
+ struct wpabuf *venue_name;
+ struct wpabuf *network_auth_type;
+ struct wpabuf *roaming_consortium;
+ struct wpabuf *ip_addr_type_availability;
+ struct wpabuf *nai_realm;
+ struct wpabuf *anqp_3gpp;
+ struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+ struct wpabuf *hs20_operator_friendly_name;
+ struct wpabuf *hs20_wan_metrics;
+ struct wpabuf *hs20_connection_capability;
+ struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
+
/**
* struct wpa_bss - BSS table
* @list: List entry for struct wpa_supplicant::bss
@@ -28,6 +47,7 @@
* @flags: information flags about the BSS/IBSS (WPA_BSS_*)
* @last_update_idx: Index of the last scan update
* @bssid: BSSID
+ * @hessid: HESSID
* @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
* @beacon_int: beacon interval in TUs (host byte order)
* @caps: capability information field in host byte order
@@ -50,6 +70,7 @@
unsigned int last_update_idx;
unsigned int flags;
u8 bssid[ETH_ALEN];
+ u8 hessid[ETH_ALEN];
u8 ssid[32];
size_t ssid_len;
int freq;
@@ -60,21 +81,7 @@
int level;
u64 tsf;
struct os_time last_update;
-#ifdef CONFIG_INTERWORKING
- struct wpabuf *anqp_venue_name;
- struct wpabuf *anqp_network_auth_type;
- struct wpabuf *anqp_roaming_consortium;
- struct wpabuf *anqp_ip_addr_type_availability;
- struct wpabuf *anqp_nai_realm;
- struct wpabuf *anqp_3gpp;
- struct wpabuf *anqp_domain_name;
-#endif /* CONFIG_INTERWORKING */
-#ifdef CONFIG_HS20
- struct wpabuf *hs20_operator_friendly_name;
- struct wpabuf *hs20_wan_metrics;
- struct wpabuf *hs20_connection_capability;
- struct wpabuf *hs20_operating_class;
-#endif /* CONFIG_HS20 */
+ struct wpa_bss_anqp *anqp;
size_t ie_len;
size_t beacon_ie_len;
/* followed by ie_len octets of IEs */
@@ -103,5 +110,6 @@
u32 vendor_type);
int wpa_bss_get_max_rate(const struct wpa_bss *bss);
int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
#endif /* BSS_H */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b89732d..be21029 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -53,42 +53,6 @@
};
-static char * wpa_config_parse_string(const char *value, size_t *len)
-{
- if (*value == '"') {
- const char *pos;
- char *str;
- value++;
- pos = os_strrchr(value, '"');
- if (pos == NULL || pos[1] != '\0')
- return NULL;
- *len = pos - value;
- str = os_malloc(*len + 1);
- if (str == NULL)
- return NULL;
- os_memcpy(str, value, *len);
- str[*len] = '\0';
- return str;
- } else {
- u8 *str;
- size_t tlen, hlen = os_strlen(value);
- if (hlen & 1)
- return NULL;
- tlen = hlen / 2;
- str = os_malloc(tlen + 1);
- if (str == NULL)
- return NULL;
- if (hexstr2bin(value, str, tlen)) {
- os_free(str);
- return NULL;
- }
- str[tlen] = '\0';
- *len = tlen;
- return (char *) str;
- }
-}
-
-
static int wpa_config_parse_str(const struct parse_data *data,
struct wpa_ssid *ssid,
int line, const char *value)
@@ -149,18 +113,6 @@
#ifndef NO_CONFIG_WRITE
-static int is_hex(const u8 *data, size_t len)
-{
- size_t i;
-
- for (i = 0; i < len; i++) {
- if (data[i] < 32 || data[i] >= 127)
- return 1;
- }
- return 0;
-}
-
-
static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
{
char *buf;
@@ -219,26 +171,6 @@
return wpa_config_write_string((const u8 *) *src, len);
}
-
-#ifdef WPA_UNICODE_SSID
-static char * wpa_config_write_str_unicode(const struct parse_data *data,
- struct wpa_ssid *ssid)
-{
- size_t len;
- char **src;
-
- src = (char **) (((u8 *) ssid) + (long) data->param1);
- if (*src == NULL)
- return NULL;
-
- if (data->param2)
- len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
- else
- len = os_strlen(*src);
-
- return wpa_config_write_string_ascii((const u8 *) *src, len);
-}
-#endif
#endif /* NO_CONFIG_WRITE */
@@ -344,6 +276,21 @@
struct wpa_ssid *ssid, int line,
const char *value)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ os_free(ssid->passphrase);
+ ssid->passphrase = NULL;
+ ssid->psk_set = 0;
+ os_free(ssid->ext_psk);
+ ssid->ext_psk = os_strdup(value + 4);
+ if (ssid->ext_psk == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+ ssid->ext_psk);
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (*value == '"') {
#ifndef CONFIG_NO_PBKDF2
const char *pos;
@@ -401,6 +348,17 @@
static char * wpa_config_write_psk(const struct parse_data *data,
struct wpa_ssid *ssid)
{
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+ char *buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (ssid->passphrase)
return wpa_config_write_string_ascii(
(const u8 *) ssid->passphrase,
@@ -685,6 +643,8 @@
*end = '\0';
if (os_strcmp(start, "CCMP") == 0)
val |= WPA_CIPHER_CCMP;
+ else if (os_strcmp(start, "GCMP") == 0)
+ val |= WPA_CIPHER_GCMP;
else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
else if (os_strcmp(start, "WEP104") == 0)
@@ -736,6 +696,16 @@
pos += ret;
}
+ if (cipher & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
+ }
+
if (cipher & WPA_CIPHER_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP",
pos == buf ? "" : " ");
@@ -789,7 +759,8 @@
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_NONE)) {
wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
"(0x%x).", line, val);
return -1;
@@ -818,8 +789,8 @@
val = wpa_config_parse_cipher(line, value);
if (val == -1)
return -1;
- if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
- WPA_CIPHER_WEP40)) {
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
"(0x%x).", line, val);
return -1;
@@ -949,7 +920,7 @@
used = 0;
len = 10;
- freqs = os_zalloc((len + 1) * sizeof(int));
+ freqs = os_calloc(len + 1, sizeof(int));
if (freqs == NULL)
return NULL;
@@ -960,7 +931,7 @@
if (used == len) {
int *n;
size_t i;
- n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
+ n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
if (n == NULL) {
os_free(freqs);
return NULL;
@@ -1089,8 +1060,8 @@
last = *end == '\0';
*end = '\0';
tmp = methods;
- methods = os_realloc(methods,
- (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1,
+ sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
os_free(buf);
@@ -1120,7 +1091,7 @@
os_free(buf);
tmp = methods;
- methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
+ methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
if (methods == NULL) {
os_free(tmp);
return -1;
@@ -1186,6 +1157,20 @@
return 0;
}
+#ifdef CONFIG_EXT_PASSWORD
+ if (os_strncmp(value, "ext:", 4) == 0) {
+ char *name = os_strdup(value + 4);
+ if (name == NULL)
+ return -1;
+ os_free(ssid->eap.password);
+ ssid->eap.password = (u8 *) name;
+ ssid->eap.password_len = os_strlen(name);
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+ return 0;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (os_strncmp(value, "hash:", 5) != 0) {
char *tmp;
size_t res_len;
@@ -1203,6 +1188,7 @@
ssid->eap.password = (u8 *) tmp;
ssid->eap.password_len = res_len;
ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1231,6 +1217,7 @@
ssid->eap.password = hash;
ssid->eap.password_len = 16;
ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+ ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
return 0;
}
@@ -1244,6 +1231,17 @@
if (ssid->eap.password == NULL)
return NULL;
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+ buf = os_zalloc(4 + ssid->eap.password_len + 1);
+ if (buf == NULL)
+ return NULL;
+ os_memcpy(buf, "ext:", 4);
+ os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+ return buf;
+ }
+#endif /* CONFIG_EXT_PASSWORD */
+
if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
return wpa_config_write_string(
ssid->eap.password, ssid->eap.password_len);
@@ -1391,18 +1389,27 @@
pos++;
if (hwaddr_aton(pos, addr)) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid "
- "p2p_client_list address '%s'.",
- line, value);
- /* continue anyway */
+ if (count == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid "
+ "p2p_client_list address '%s'.",
+ line, value);
+ os_free(buf);
+ return -1;
+ }
+ /* continue anyway since this could have been from a
+ * truncated configuration file line */
+ wpa_printf(MSG_INFO, "Line %d: Ignore likely "
+ "truncated p2p_client_list address '%s'",
+ line, pos);
} else {
- n = os_realloc(buf, (count + 1) * ETH_ALEN);
+ n = os_realloc_array(buf, count + 1, ETH_ALEN);
if (n == NULL) {
os_free(buf);
return -1;
}
buf = n;
- os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN);
+ os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
+ os_memcpy(buf, addr, ETH_ALEN);
count++;
wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
addr, ETH_ALEN);
@@ -1436,10 +1443,10 @@
pos = value;
end = value + 20 * ssid->num_p2p_clients;
- for (i = 0; i < ssid->num_p2p_clients; i++) {
+ for (i = ssid->num_p2p_clients; i > 0; i--) {
res = os_snprintf(pos, end - pos, MACSTR " ",
MAC2STR(ssid->p2p_client_list +
- i * ETH_ALEN));
+ (i - 1) * ETH_ALEN));
if (res < 0 || res >= end - pos) {
os_free(value);
return NULL;
@@ -1500,15 +1507,6 @@
OFFSET(f), (void *) 0
#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
OFFSET(eap.f), (void *) 0
-#ifdef WPA_UNICODE_SSID
-/* STR_* variants that do not force conversion to ASCII */
-#define _STR_UNICODE(f) #f, wpa_config_parse_str, wpa_config_write_str_unicode, OFFSET(f)
-#define STR_UNICODE(f) _STR_UNICODE(f), NULL, NULL, NULL, 0
-#define _STR_LEN_UNICODE(f) _STR_UNICODE(f), OFFSET(f ## _len)
-#define STR_LEN_UNICODE(f) _STR_LEN_UNICODE(f), NULL, NULL, 0
-#define _STR_RANGE_UNICODE(f, min, max) _STR_LEN_UNICODE(f), (void *) (min), (void *) (max)
-#define STR_RANGE_UNICODE(f, min, max) _STR_RANGE_UNICODE(f, min, max), 0
-#endif
#endif /* NO_CONFIG_WRITE */
/* INT: Define an integer variable */
@@ -1553,11 +1551,7 @@
* functions.
*/
static const struct parse_data ssid_fields[] = {
-#ifdef WPA_UNICODE_SSID
- { STR_RANGE_UNICODE(ssid, 0, MAX_SSID_LEN) },
-#else
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
-#endif
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
{ FUNC_KEY(psk) },
@@ -1646,15 +1640,6 @@
{ INT(dtim_period) },
};
-#ifdef WPA_UNICODE_SSID
-#undef _STR_UNICODE
-#undef STR_UNICODE
-#undef _STR_LEN_UNICODE
-#undef STR_LEN_UNICODE
-#undef _STR_RANGE_UNICODE
-#undef STR_RANGE_UNICODE
-#endif
-
#undef OFFSET
#undef _STR
#undef STR
@@ -1706,8 +1691,8 @@
}
/* First network for this priority - add a new priority list */
- nlist = os_realloc(config->pssid,
- (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ nlist = os_realloc_array(config->pssid, config->num_prio + 1,
+ sizeof(struct wpa_ssid *));
if (nlist == NULL)
return -1;
@@ -1813,6 +1798,7 @@
{
os_free(ssid->ssid);
os_free(ssid->passphrase);
+ os_free(ssid->ext_psk);
#ifdef IEEE8021X_EAPOL
eap_peer_config_free(&ssid->eap);
#endif /* IEEE8021X_EAPOL */
@@ -1840,6 +1826,9 @@
os_free(cred->imsi);
os_free(cred->milenage);
os_free(cred->domain);
+ os_free(cred->eap_method);
+ os_free(cred->phase1);
+ os_free(cred->phase2);
os_free(cred);
}
@@ -1905,6 +1894,7 @@
wpabuf_free(config->wps_nfc_dh_pubkey);
wpabuf_free(config->wps_nfc_dh_privkey);
wpabuf_free(config->wps_nfc_dev_pw);
+ os_free(config->ext_password_backend);
os_free(config);
}
@@ -2139,7 +2129,7 @@
get_keys = get_keys && ssid->export_keys;
- props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
+ props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
if (!props)
return NULL;
@@ -2267,8 +2257,7 @@
void wpa_config_update_psk(struct wpa_ssid *ssid)
{
#ifndef CONFIG_NO_PBKDF2
- pbkdf2_sha1(ssid->passphrase,
- (char *) ssid->ssid, ssid->ssid_len, 4096,
+ pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
ssid->psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
ssid->psk, PMK_LEN);
@@ -2293,6 +2282,31 @@
return 0;
}
+ if (os_strcmp(var, "eap") == 0) {
+ struct eap_method_type method;
+ method.method = eap_peer_get_type(value, &method.vendor);
+ if (method.vendor == EAP_VENDOR_IETF &&
+ method.method == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+ "for a credential", line, value);
+ return -1;
+ }
+ os_free(cred->eap_method);
+ cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+ if (cred->eap_method == NULL)
+ return -1;
+ os_memcpy(cred->eap_method, &method, sizeof(method));
+ return 0;
+ }
+
+ if (os_strcmp(var, "password") == 0 &&
+ os_strncmp(value, "ext:", 4) == 0) {
+ os_free(cred->password);
+ cred->password = os_strdup(value);
+ cred->ext_password = 1;
+ return 0;
+ }
+
val = wpa_config_parse_string(value, &len);
if (val == NULL) {
wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
@@ -2315,6 +2329,7 @@
if (os_strcmp(var, "password") == 0) {
os_free(cred->password);
cred->password = val;
+ cred->ext_password = 0;
return 0;
}
@@ -2360,6 +2375,32 @@
return 0;
}
+ if (os_strcmp(var, "phase1") == 0) {
+ os_free(cred->phase1);
+ cred->phase1 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "phase2") == 0) {
+ os_free(cred->phase2);
+ cred->phase2 = val;
+ return 0;
+ }
+
+ if (os_strcmp(var, "roaming_consortium") == 0) {
+ if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "roaming_consortium length %d (3..15 "
+ "expected)", line, (int) len);
+ os_free(val);
+ return -1;
+ }
+ os_memcpy(cred->roaming_consortium, val, len);
+ cred->roaming_consortium_len = len;
+ os_free(val);
+ return 0;
+ }
+
if (line) {
wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
line, var);
@@ -2530,6 +2571,15 @@
const char *driver_param)
{
struct wpa_config *config;
+ const int aCWmin = 4, aCWmax = 10;
+ const struct hostapd_wmm_ac_params ac_bk =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wmm_ac_params ac_be =
+ { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+ const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
config = os_zalloc(sizeof(*config));
if (config == NULL)
@@ -2539,11 +2589,16 @@
config->fast_reauth = DEFAULT_FAST_REAUTH;
config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
+ config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
config->max_num_sta = DEFAULT_MAX_NUM_STA;
config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+ config->wmm_ac_params[0] = ac_be;
+ config->wmm_ac_params[1] = ac_bk;
+ config->wmm_ac_params[2] = ac_vi;
+ config->wmm_ac_params[3] = ac_vo;
if (ctrl_interface)
config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2836,7 +2891,8 @@
pos2++;
chan = atoi(pos2);
- n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel));
+ n = os_realloc_array(pref, num + 1,
+ sizeof(struct p2p_channel));
if (n == NULL)
goto fail;
pref = n;
@@ -2950,6 +3006,7 @@
{ INT(bss_expiration_age), 0 },
{ INT(bss_expiration_scan_count), 0 },
{ INT_RANGE(filter_ssids, 0, 1), 0 },
+ { INT_RANGE(filter_rssi, -100, 0), 0 },
{ INT(max_num_sta), 0 },
{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
#ifdef CONFIG_HS20
@@ -2963,7 +3020,10 @@
{ INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
{ BIN(wps_nfc_dh_pubkey), 0 },
{ BIN(wps_nfc_dh_privkey), 0 },
- { BIN(wps_nfc_dev_pw), 0 }
+ { BIN(wps_nfc_dev_pw), 0 },
+ { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+ { INT(p2p_go_max_inactivity), 0 },
+ { INT_RANGE(auto_interworking, 0, 1), 0 },
};
#undef FUNC
@@ -2998,6 +3058,25 @@
break;
}
if (i == NUM_GLOBAL_FIELDS) {
+#ifdef CONFIG_AP
+ if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
+ char *tmp = os_strchr(pos, '=');
+ if (tmp == NULL) {
+ if (line < 0)
+ return -1;
+ wpa_printf(MSG_ERROR, "Line %d: invalid line "
+ "'%s'", line, pos);
+ return -1;
+ }
+ *tmp++ = '\0';
+ if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
+ tmp)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+ "AC item", line);
+ return -1;
+ }
+ }
+#endif /* CONFIG_AP */
if (line < 0)
return -1;
wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 46c4da2..b889ab8 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -18,6 +18,7 @@
#define DEFAULT_FAST_REAUTH 1
#define DEFAULT_P2P_GO_INTENT 7
#define DEFAULT_P2P_INTRA_BSS 1
+#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
#define DEFAULT_BSS_MAX_COUNT 200
#define DEFAULT_BSS_EXPIRATION_AGE 180
#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
@@ -26,6 +27,7 @@
#include "config_ssid.h"
#include "wps/wps.h"
+#include "common/ieee802_11_common.h"
struct wpa_cred {
@@ -81,6 +83,11 @@
char *password;
/**
+ * ext_password - Whether password is a name for external storage
+ */
+ int ext_password;
+
+ /**
* ca_cert - CA certificate for Interworking network selection
*/
char *ca_cert;
@@ -148,6 +155,47 @@
* whether the AP is operated by the Home SP.
*/
char *domain;
+
+ /**
+ * roaming_consortium - Roaming Consortium OI
+ *
+ * If roaming_consortium_len is non-zero, this field contains the
+ * Roaming Consortium OI that can be used to determine which access
+ * points support authentication with this credential. This is an
+ * alternative to the use of the realm parameter. When using Roaming
+ * Consortium to match the network, the EAP parameters need to be
+ * pre-configured with the credential since the NAI Realm information
+ * may not be available or fetched.
+ */
+ u8 roaming_consortium[15];
+
+ /**
+ * roaming_consortium_len - Length of roaming_consortium
+ */
+ size_t roaming_consortium_len;
+
+ /**
+ * eap_method - EAP method to use
+ *
+ * Pre-configured EAP method to use with this credential or %NULL to
+ * indicate no EAP method is selected, i.e., the method will be
+ * selected automatically based on ANQP information.
+ */
+ struct eap_method_type *eap_method;
+
+ /**
+ * phase1 - Phase 1 (outer authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase1;
+
+ /**
+ * phase2 - Phase 2 (inner authentication) parameters
+ *
+ * Pre-configured EAP parameters or %NULL.
+ */
+ char *phase2;
};
@@ -165,6 +213,7 @@
#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
/**
* struct wpa_config - wpa_supplicant configuration data
@@ -575,6 +624,14 @@
int filter_ssids;
/**
+ * filter_rssi - RSSI-based scan result filtering
+ *
+ * 0 = do not filter scan results
+ * -n = filter scan results below -n dBm
+ */
+ int filter_rssi;
+
+ /**
* max_num_sta - Maximum number of STAs in an AP/P2P GO
*/
unsigned int max_num_sta;
@@ -661,6 +718,35 @@
* wps_nfc_dh_pubkey - NFC Device Password for password token
*/
struct wpabuf *wps_nfc_dev_pw;
+
+ /**
+ * ext_password_backend - External password backend or %NULL if none
+ *
+ * format: <backend name>[:<optional backend parameters>]
+ */
+ char *ext_password_backend;
+
+ /*
+ * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity
+ *
+ * This timeout value is used in P2P GO mode to clean up
+ * inactive stations.
+ * By default: 300 seconds.
+ */
+ int p2p_go_max_inactivity;
+
+ struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+ /**
+ * auto_interworking - Whether to use network selection automatically
+ *
+ * 0 = do not automatically go through Interworking network selection
+ * (i.e., require explicit interworking_select command for this)
+ * 1 = perform Interworking network selection if one or more
+ * credentials have been configured and scan did not find a
+ * matching network block
+ */
+ int auto_interworking;
};
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 8badc7b..531957a 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -19,6 +19,29 @@
#include "p2p/p2p.h"
+static int newline_terminated(const char *buf, size_t buflen)
+{
+ size_t len = os_strlen(buf);
+ if (len == 0)
+ return 0;
+ if (len == buflen - 1 && buf[buflen - 1] != '\r' &&
+ buf[len - 1] != '\n')
+ return 0;
+ return 1;
+}
+
+
+static void skip_line_end(FILE *stream)
+{
+ char buf[100];
+ while (fgets(buf, sizeof(buf), stream)) {
+ buf[sizeof(buf) - 1] = '\0';
+ if (newline_terminated(buf, sizeof(buf)))
+ return;
+ }
+}
+
+
/**
* wpa_config_get_line - Read the next configuration file line
* @s: Buffer for the line
@@ -41,6 +64,15 @@
while (fgets(s, size, stream)) {
(*line)++;
s[size - 1] = '\0';
+ if (!newline_terminated(s, size)) {
+ /*
+ * The line was truncated - skip rest of it to avoid
+ * confusing error messages.
+ */
+ wpa_printf(MSG_INFO, "Long line in configuration file "
+ "truncated");
+ skip_line_end(stream);
+ }
pos = s;
/* Skip white space from the beginning of line. */
@@ -99,12 +131,6 @@
wpa_config_update_psk(ssid);
}
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
- "management, but no PSK configured.", line);
- errors++;
- }
-
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
@@ -123,7 +149,7 @@
{
struct wpa_ssid *ssid;
int errors = 0, end = 0;
- char buf[256], *pos, *pos2;
+ char buf[2000], *pos, *pos2;
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
*line);
@@ -329,11 +355,17 @@
int cred_id = 0;
config = wpa_config_alloc_empty(NULL, NULL);
- if (config == NULL)
+ if (config == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to allocate config file "
+ "structure");
return NULL;
+ }
+
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
if (f == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open config file '%s', "
+ "error: %s", name, strerror(errno));
os_free(config);
return NULL;
}
@@ -378,6 +410,8 @@
} else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
if (wpa_config_process_blob(config, f, &line, pos + 12)
< 0) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "process blob.", line);
errors++;
continue;
}
@@ -875,6 +909,16 @@
write_global_bin(f, "wps_nfc_dh_pubkey", config->wps_nfc_dh_pubkey);
write_global_bin(f, "wps_nfc_dh_privkey", config->wps_nfc_dh_privkey);
write_global_bin(f, "wps_nfc_dev_pw", config->wps_nfc_dev_pw);
+
+ if (config->ext_password_backend)
+ fprintf(f, "ext_password_backend=%s\n",
+ config->ext_password_backend);
+ if (config->p2p_go_max_inactivity != DEFAULT_P2P_GO_MAX_INACTIVITY)
+ fprintf(f, "p2p_go_max_inactivity=%d\n",
+ config->p2p_go_max_inactivity);
+ if (config->auto_interworking)
+ fprintf(f, "auto_interworking=%d\n",
+ config->auto_interworking);
}
#endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 59ec309..ff97379 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -141,6 +141,14 @@
char *passphrase;
/**
+ * ext_psk - PSK/passphrase name in external storage
+ *
+ * If this is set, PSK/passphrase will be fetched from external storage
+ * when requesting association with the network.
+ */
+ char *ext_psk;
+
+ /**
* pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
*/
int pairwise_cipher;
@@ -356,6 +364,8 @@
*/
int frequency;
+ int ht40;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
@@ -421,6 +431,10 @@
*/
size_t num_p2p_clients;
+#ifndef P2P_MAX_STORED_CLIENTS
+#define P2P_MAX_STORED_CLIENTS 100
+#endif /* P2P_MAX_STORED_CLIENTS */
+
/**
* p2p_group - Network generated as a P2P group (used internally)
*/
@@ -443,6 +457,7 @@
* WPS or similar so that they may be exported.
*/
int export_keys;
+
#ifdef ANDROID_P2P
/**
* assoc_retry - Number of times association should be retried.
@@ -511,6 +526,16 @@
* By default: 2
*/
int dtim_period;
+
+ /**
+ * auth_failures - Number of consecutive authentication failures
+ */
+ unsigned int auth_failures;
+
+ /**
+ * disabled_until - Network block disabled until this time if non-zero
+ */
+ struct os_time disabled_until;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index de2ec58..6d9876c 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -344,13 +344,6 @@
wpa_config_update_psk(ssid);
}
- if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
- "but no PSK configured for network '" TSTR "'.",
- netw);
- errors++;
- }
-
if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
!(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index c703002..480c077 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "eap_peer/eap.h"
#include "eapol_supp/eapol_supp_sm.h"
@@ -29,6 +30,7 @@
#include "p2p_supplicant.h"
#include "p2p/p2p.h"
#include "hs20_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bss.h"
#include "scan.h"
@@ -98,6 +100,9 @@
ssid = ssid->next;
}
+ if (wpa_s->conf->filter_rssi)
+ params.filter_rssi = wpa_s->conf->filter_rssi;
+
ret = wpa_drv_sched_scan(wpa_s, ¶ms, 10 * 1000);
os_free(params.filter_ssids);
if (ret == 0)
@@ -130,7 +135,7 @@
os_free(filter);
return -1;
}
- n = os_realloc(filter, (count + 1) * ETH_ALEN);
+ n = os_realloc_array(filter, count + 1, ETH_ALEN);
if (n == NULL) {
os_free(filter);
return -1;
@@ -280,6 +285,10 @@
}
} else if (os_strcasecmp(cmd, "ps") == 0) {
ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ wifi_display_enable(wpa_s->global, !!atoi(value));
+#endif /* CONFIG_WIFI_DISPLAY */
} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
ret = set_bssid_filter(wpa_s, value);
} else {
@@ -307,6 +316,14 @@
res = os_snprintf(buf, buflen, "%c%c",
wpa_s->conf->country[0],
wpa_s->conf->country[1]);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+ res = os_snprintf(buf, buflen, "%d",
+ wpa_s->global->wifi_display);
+ if (res < 0 || (unsigned int) res >= buflen)
+ return -1;
+ return res;
+#endif /* CONFIG_WIFI_DISPLAY */
}
if (res < 0 || (unsigned int) res >= buflen)
@@ -472,7 +489,7 @@
u8 *_p2p_dev_addr = NULL;
#endif /* CONFIG_AP */
- if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+ if (cmd == NULL || os_strcmp(cmd, "any") == 0 || cmd[0] == '\0') {
_bssid = NULL;
#ifdef CONFIG_P2P
} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
@@ -1121,7 +1138,9 @@
#ifdef CONFIG_HS20
if (wpa_s->current_bss &&
- wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE)) {
+ wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+ wpa_s->wpa_proto == WPA_PROTO_RSN &&
+ wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
ret = os_snprintf(pos, end - pos, "hs20=1\n");
if (ret < 0 || ret >= end - pos)
return pos - buf;
@@ -1377,10 +1396,12 @@
if (ret < 0 || ret >= end - pos)
return pos - buf;
pos += ret;
- ret = os_snprintf(pos, end - pos, "\t%s%s%s",
+ ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
ssid == wpa_s->current_ssid ?
"[CURRENT]" : "",
ssid->disabled ? "[DISABLED]" : "",
+ ssid->disabled_until.sec ?
+ "[TEMP-DISABLED]" : "",
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
"");
if (ret < 0 || ret >= end - pos)
@@ -1441,6 +1462,13 @@
pos += ret;
first = 0;
}
+ if (cipher & WPA_CIPHER_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
+ first = 0;
+ }
return pos;
}
@@ -1640,7 +1668,7 @@
pos += ret;
}
#ifdef CONFIG_HS20
- if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+ if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
ret = os_snprintf(pos, end - pos, "[HS20]");
if (ret < 0 || ret >= end - pos)
return -1;
@@ -1853,8 +1881,7 @@
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid)
wpas_notify_network_removed(wpa_s, ssid);
- if (ssid == NULL ||
- wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ if (ssid == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
"id=%d", id);
return -1;
@@ -1878,6 +1905,12 @@
wpa_supplicant_disassociate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
}
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
+ "network id=%d", id);
+ return -1;
+ }
+
return 0;
}
@@ -2163,6 +2196,14 @@
first = 0;
}
+ if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
if (ret < 0 || ret >= end - pos)
@@ -2211,6 +2252,14 @@
first = 0;
}
+ if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ first = 0;
+ }
+
if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
if (ret < 0 || ret >= end - pos)
@@ -2406,7 +2455,7 @@
hmode = "A";
break;
default:
- return pos - buf;
+ continue;
}
ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
if (ret < 0 || ret >= end - pos)
@@ -2414,6 +2463,8 @@
pos += ret;
chnl = wpa_s->hw.modes[j].channels;
for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+ if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+ continue;
ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
if (ret < 0 || ret >= end - pos)
return pos - buf;
@@ -2715,28 +2766,54 @@
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
+ struct wpabuf *wfd;
+ ie = (const u8 *) (bss + 1);
+ wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
+ WFD_IE_VENDOR_TYPE);
+ if (wfd) {
+ ret = os_snprintf(pos, end - pos, "wfd_subelems=");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos,
+ wpabuf_head(wfd),
+ wpabuf_len(wfd));
+ wpabuf_free(wfd);
+
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
#ifdef CONFIG_INTERWORKING
- if (mask & WPA_BSS_MASK_INTERNETW) {
+ if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+ struct wpa_bss_anqp *anqp = bss->anqp;
pos = anqp_add_hex(pos, end, "anqp_venue_name",
- bss->anqp_venue_name);
+ anqp->venue_name);
pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
- bss->anqp_network_auth_type);
+ anqp->network_auth_type);
pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
- bss->anqp_roaming_consortium);
+ anqp->roaming_consortium);
pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
- bss->anqp_ip_addr_type_availability);
+ anqp->ip_addr_type_availability);
pos = anqp_add_hex(pos, end, "anqp_nai_realm",
- bss->anqp_nai_realm);
- pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
+ anqp->nai_realm);
+ pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
pos = anqp_add_hex(pos, end, "anqp_domain_name",
- bss->anqp_domain_name);
+ anqp->domain_name);
#ifdef CONFIG_HS20
pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
- bss->hs20_operator_friendly_name);
+ anqp->hs20_operator_friendly_name);
pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
- bss->hs20_wan_metrics);
+ anqp->hs20_wan_metrics);
pos = anqp_add_hex(pos, end, "hs20_connection_capability",
- bss->hs20_connection_capability);
+ anqp->hs20_connection_capability);
#endif /* CONFIG_HS20 */
}
#endif /* CONFIG_INTERWORKING */
@@ -2904,6 +2981,19 @@
}
+static int wpa_supplicant_ctrl_iface_bss_flush(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int flush_age = atoi(cmd);
+
+ if (flush_age == 0)
+ wpa_bss_flush(wpa_s);
+ else
+ wpa_bss_flush_by_age(wpa_s, flush_age);
+ return 0;
+}
+
+
static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
{
wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
@@ -2978,6 +3068,7 @@
enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
u8 dev_id[ETH_ALEN], *_dev_id = NULL;
char *pos;
+ unsigned int search_delay;
if (os_strstr(cmd, "type=social"))
type = P2P_FIND_ONLY_SOCIAL;
@@ -2992,7 +3083,15 @@
_dev_id = dev_id;
}
- return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id);
+ pos = os_strstr(cmd, "delay=");
+ if (pos) {
+ pos += 6;
+ search_delay = atoi(pos);
+ } else
+ search_delay = wpas_p2p_search_delay(wpa_s);
+
+ return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
+ search_delay);
}
@@ -3012,10 +3111,12 @@
int go_intent = -1;
int freq = 0;
int pd;
+ int ht40;
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
* [persistent|persistent=<network id>]
- * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc] */
+ * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+ * [ht40] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -3043,6 +3144,7 @@
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
+ ht40 = os_strstr(pos, " ht40") != NULL;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -3082,7 +3184,8 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
- auth, go_intent, freq, persistent_id, pd);
+ auth, go_intent, freq, persistent_id, pd,
+ ht40);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -3182,6 +3285,10 @@
return -1;
pos++;
ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
+ ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
+#endif /* CONFIG_WIFI_DISPLAY */
} else {
len = os_strlen(pos);
if (len & 1)
@@ -3441,6 +3548,8 @@
int id;
struct wpa_ssid *ssid;
u8 peer[ETH_ALEN];
+ int freq = 0;
+ int ht40;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -3457,7 +3566,18 @@
return -1;
}
- return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL);
+ pos = os_strstr(cmd, " freq=");
+ if (pos) {
+ pos += 6;
+ freq = atoi(pos);
+ if (freq <= 0)
+ return -1;
+ }
+
+ ht40 = os_strstr(cmd, " ht40") != NULL;
+
+ return wpas_p2p_invite(wpa_s, pos ? peer : NULL, ssid, NULL, freq,
+ ht40);
}
@@ -3504,7 +3624,7 @@
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- char *cmd, int freq)
+ char *cmd, int freq, int ht40)
{
int id;
struct wpa_ssid *ssid;
@@ -3518,26 +3638,31 @@
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0;
+ int freq = 0, ht40;
char *pos;
pos = os_strstr(cmd, "freq=");
if (pos)
freq = atoi(pos + 5);
+ ht40 = os_strstr(cmd, "ht40") != NULL;
+
if (os_strncmp(cmd, "persistent=", 11) == 0)
- return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq);
+ return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
+ ht40);
if (os_strcmp(cmd, "persistent") == 0 ||
os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq);
+ return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
if (os_strncmp(cmd, "freq=", 5) == 0)
- return wpas_p2p_group_add(wpa_s, 0, freq);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ if (ht40)
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
cmd);
@@ -3640,8 +3765,8 @@
*/
pos = param;
while (pos && pos[0]) {
- n = os_realloc(freq,
- (count + 1) * sizeof(struct wpa_freq_range));
+ n = os_realloc_array(freq, count + 1,
+ sizeof(struct wpa_freq_range));
if (n == NULL) {
os_free(freq);
return -1;
@@ -3944,6 +4069,122 @@
return anqp_send_req(wpa_s, dst_addr, id, num_id);
}
+
+
+static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+ u8 dst_addr[ETH_ALEN];
+ struct wpabuf *advproto, *query = NULL;
+ int used, ret = -1;
+ char *pos, *end;
+ size_t len;
+
+ used = hwaddr_aton2(cmd, dst_addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+
+ /* Advertisement Protocol ID */
+ end = os_strchr(pos, ' ');
+ if (end)
+ len = end - pos;
+ else
+ len = os_strlen(pos);
+ if (len & 0x01)
+ return -1;
+ len /= 2;
+ if (len == 0)
+ return -1;
+ advproto = wpabuf_alloc(len);
+ if (advproto == NULL)
+ return -1;
+ if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
+ goto fail;
+
+ if (end) {
+ /* Optional Query Request */
+ pos = end + 1;
+ while (*pos == ' ')
+ pos++;
+
+ len = os_strlen(pos);
+ if (len) {
+ if (len & 0x01)
+ goto fail;
+ len /= 2;
+ if (len == 0)
+ goto fail;
+ query = wpabuf_alloc(len);
+ if (query == NULL)
+ goto fail;
+ if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
+ goto fail;
+ }
+ }
+
+ ret = gas_send_request(wpa_s, dst_addr, advproto, query);
+
+fail:
+ wpabuf_free(advproto);
+ wpabuf_free(query);
+
+ return ret;
+}
+
+
+static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
+ size_t buflen)
+{
+ u8 addr[ETH_ALEN];
+ int dialog_token;
+ int used;
+ char *pos;
+ size_t resp_len, start, requested_len;
+
+ if (!wpa_s->last_gas_resp)
+ return -1;
+
+ used = hwaddr_aton2(cmd, addr);
+ if (used < 0)
+ return -1;
+
+ pos = cmd + used;
+ while (*pos == ' ')
+ pos++;
+ dialog_token = atoi(pos);
+
+ if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
+ dialog_token != wpa_s->last_gas_dialog_token)
+ return -1;
+
+ resp_len = wpabuf_len(wpa_s->last_gas_resp);
+ start = 0;
+ requested_len = resp_len;
+
+ pos = os_strchr(pos, ' ');
+ if (pos) {
+ start = atoi(pos);
+ if (start > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ pos = os_strchr(pos, ',');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ requested_len = atoi(pos);
+ if (start + requested_len > resp_len)
+ return os_snprintf(buf, buflen, "FAIL-Invalid range");
+ }
+
+ if (requested_len * 2 + 1 > buflen)
+ return os_snprintf(buf, buflen, "FAIL-Too long response");
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(wpa_s->last_gas_resp) + start,
+ requested_len);
+}
#endif /* CONFIG_INTERWORKING */
@@ -4109,6 +4350,7 @@
return ret;
}
+
static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
size_t buflen)
{
@@ -4120,8 +4362,8 @@
return -1;
ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
- sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
- if (ret < 0 || (unsigned int) ret > buflen)
+ sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
+ if (ret < 0 || (size_t) ret > buflen)
return -1;
return ret;
}
@@ -4140,6 +4382,7 @@
}
#endif
+
char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
@@ -4172,6 +4415,9 @@
if (os_strcmp(buf, "PING") == 0) {
os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
+ } else if (os_strcmp(buf, "IFNAME") == 0) {
+ reply_len = os_strlen(wpa_s->ifname);
+ os_memcpy(reply, wpa_s->ifname, reply_len);
} else if (os_strncmp(buf, "RELOG", 5) == 0) {
if (wpa_debug_reopen_file() < 0)
reply_len = -1;
@@ -4362,7 +4608,7 @@
if (wpas_p2p_group_remove(wpa_s, buf + 17))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
- if (wpas_p2p_group_add(wpa_s, 0, 0))
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -4434,6 +4680,14 @@
if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
reply_len = -1;
#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+ } else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
+ if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
+ reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
+ reply, reply_size);
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
if (interworking_fetch_anqp(wpa_s) < 0)
@@ -4450,6 +4704,12 @@
} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
if (get_anqp(wpa_s, buf + 9) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
+ if (gas_request(wpa_s, buf + 12) < 0)
+ reply_len = -1;
+ } else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
+ reply_len = gas_response_get(wpa_s, buf + 17, reply,
+ reply_size);
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
} else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
@@ -4611,6 +4871,9 @@
if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
buf + 17))
reply_len = -1;
+ } else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
+ if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
+ reply_len = -1;
#ifdef CONFIG_TDLS
} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index c831e6c..994f9b1 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -163,6 +163,8 @@
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -174,6 +176,8 @@
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -266,6 +270,7 @@
{
struct ctrl_iface_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -285,13 +290,25 @@
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port--;
+ if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
@@ -442,6 +459,8 @@
perror("recvfrom(ctrl_iface)");
return;
}
+
+#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
/*
* The OS networking stack is expected to drop this kind of
@@ -453,6 +472,8 @@
"source %s", inet_ntoa(from.sin_addr));
return;
}
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
buf[res] = '\0';
if (os_strcmp(buf, "GET_COOKIE") == 0) {
@@ -502,6 +523,7 @@
{
struct ctrl_iface_global_priv *priv;
struct sockaddr_in addr;
+ int port = WPA_GLOBAL_CTRL_IFACE_PORT;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -523,13 +545,26 @@
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ addr.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+try_again:
+ addr.sin_port = htons(port);
if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ port++;
+ if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
+ WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
+ goto try_again;
perror("bind(AF_INET)");
goto fail;
}
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
eloop_register_read_sock(priv->sock,
wpa_supplicant_global_ctrl_iface_receive,
global, priv);
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 8dba46d..5d81b43 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -11,6 +11,8 @@
#include <sys/stat.h>
#include <grp.h>
#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
#ifdef ANDROID
#include <cutils/sockets.h>
#endif /* ANDROID */
@@ -184,7 +186,7 @@
wpa_s = eloop_ctx;
}
os_memmove(ifname, ifend, strlen(ifend) + 1);
- wpa_printf(MSG_DEBUG, "wpa_s %p cmd %s", wpa_s, buf);
+ wpa_printf(MSG_INFO, "wpa_s %p cmd %s", wpa_s, buf);
}
#endif /* defined CONFIG_P2P && defined ANDROID_P2P */
reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
@@ -282,6 +284,7 @@
char *buf, *dir = NULL, *gid_str = NULL;
struct group *grp;
char *endp;
+ int flags;
priv = os_zalloc(sizeof(*priv));
if (priv == NULL)
@@ -428,6 +431,20 @@
#ifdef ANDROID
havesock:
#endif /* ANDROID */
+
+ /*
+ * Make socket non-blocking so that we don't hang forever if
+ * target dies unexpectedly.
+ */
+ flags = fcntl(priv->sock, F_GETFL);
+ if (flags >= 0) {
+ flags |= O_NONBLOCK;
+ if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+ perror("fcntl(ctrl, O_NONBLOCK)");
+ /* Not fatal, continue on.*/
+ }
+ }
+
eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
wpa_s, priv);
wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 67924e0..61a9430 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -738,7 +738,7 @@
entry->bytearray_value = NULL;
entry->array_type = DBUS_TYPE_BYTE;
- buffer = os_zalloc(BYTE_ARRAY_ITEM_SIZE * BYTE_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(BYTE_ARRAY_CHUNK_SIZE, BYTE_ARRAY_ITEM_SIZE);
if (!buffer)
return FALSE;
@@ -748,8 +748,9 @@
char byte;
if ((count % BYTE_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, BYTE_ARRAY_ITEM_SIZE *
- (count + BYTE_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + BYTE_ARRAY_CHUNK_SIZE,
+ BYTE_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -795,7 +796,7 @@
entry->strarray_value = NULL;
entry->array_type = DBUS_TYPE_STRING;
- buffer = os_zalloc(STR_ARRAY_ITEM_SIZE * STR_ARRAY_CHUNK_SIZE);
+ buffer = os_calloc(STR_ARRAY_CHUNK_SIZE, STR_ARRAY_ITEM_SIZE);
if (buffer == NULL)
return FALSE;
@@ -806,8 +807,9 @@
char *str;
if ((count % STR_ARRAY_CHUNK_SIZE) == 0 && count != 0) {
- nbuffer = os_realloc(buffer, STR_ARRAY_ITEM_SIZE *
- (count + STR_ARRAY_CHUNK_SIZE));
+ nbuffer = os_realloc_array(
+ buffer, count + STR_ARRAY_CHUNK_SIZE,
+ STR_ARRAY_ITEM_SIZE);
if (nbuffer == NULL) {
os_free(buffer);
wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
@@ -871,8 +873,8 @@
buflen += BIN_ARRAY_CHUNK_SIZE;
- newbuf = os_realloc(entry->binarray_value,
- buflen * BIN_ARRAY_ITEM_SIZE);
+ newbuf = os_realloc_array(entry->binarray_value,
+ buflen, BIN_ARRAY_ITEM_SIZE);
if (!newbuf)
goto cleanup;
entry->binarray_value = newbuf;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index a9957ab..4eeb93a 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -1104,7 +1104,6 @@
DBusMessage *msg;
DBusMessageIter iter, dict_iter;
struct wpas_dbus_priv *iface;
- char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
char group_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
iface = wpa_s->parent->global->dbus;
@@ -1142,14 +1141,8 @@
client ? "client" : "GO"))
goto nomem;
- os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
- "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
- wpa_s->parent->dbus_new_path, network_id);
-
if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
group_obj_path) ||
- !wpa_dbus_dict_append_object_path(&dict_iter, "network_object",
- net_obj_path) ||
!wpa_dbus_dict_close_write(&iter, &dict_iter))
goto nomem;
@@ -2391,6 +2384,12 @@
END_ARGS
}
},
+ { "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+ {
+ END_ARGS
+ }
+ },
{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
{
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 8145a70..5668e1a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -609,6 +609,7 @@
out:
os_free(driver);
os_free(ifname);
+ os_free(confname);
os_free(bridge_ifname);
return reply;
@@ -870,7 +871,7 @@
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
num++;
- paths = os_zalloc(num * sizeof(char*));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -1158,8 +1159,9 @@
#define FREQS_ALLOC_CHUNK 32
if (freqs_num % FREQS_ALLOC_CHUNK == 0) {
- nfreqs = os_realloc(freqs, sizeof(int) *
- (freqs_num + FREQS_ALLOC_CHUNK));
+ nfreqs = os_realloc_array(
+ freqs, freqs_num + FREQS_ALLOC_CHUNK,
+ sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
@@ -1179,8 +1181,7 @@
dbus_message_iter_next(&array_iter);
}
- nfreqs = os_realloc(freqs,
- sizeof(int) * (freqs_num + 1));
+ nfreqs = os_realloc_array(freqs, freqs_num + 1, sizeof(int));
if (nfreqs == NULL)
os_free(freqs);
freqs = nfreqs;
@@ -1404,6 +1405,33 @@
/**
+ * wpas_dbus_handler_reassociate - Reassociate to current AP
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NotConnected DBus error message if not connected
+ * or NULL otherwise.
+ *
+ * Handler function for "Reassociate" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->current_ssid != NULL) {
+ wpa_s->normal_scans = 0;
+ wpa_supplicant_reinit_autoscan(wpa_s);
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return NULL;
+ }
+
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_NOT_CONNECTED,
+ "This interface is not connected");
+}
+
+
+/**
* wpas_dbus_handler_remove_network - Remove a configured network
* @message: Pointer to incoming dbus message
* @wpa_s: wpa_supplicant structure for a network interface
@@ -1901,6 +1929,12 @@
goto nomem;
}
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip"))
@@ -1942,6 +1976,12 @@
goto nomem;
}
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "gcmp"))
+ goto nomem;
+ }
+
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
if (!wpa_dbus_dict_string_array_add_element(
&iter_array, "tkip"))
@@ -2430,7 +2470,7 @@
void *user_data)
{
struct wpa_supplicant *wpa_s = user_data;
- dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age;
+ dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_scan_count;
return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
&expire_count, error);
@@ -2759,7 +2799,7 @@
unsigned int i = 0;
dbus_bool_t success = FALSE;
- paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
+ paths = os_calloc(wpa_s->num_bss, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -2822,7 +2862,7 @@
if (!network_is_persistent_group(ssid))
num++;
- paths = os_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -3154,7 +3194,7 @@
{
DBusMessageIter iter_dict, variant_iter;
const char *group;
- const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
+ const char *pairwise[3]; /* max 3 pairwise ciphers is supported */
const char *key_mgmt[7]; /* max 7 key managements may be supported */
int n;
@@ -3197,6 +3237,9 @@
case WPA_CIPHER_CCMP:
group = "ccmp";
break;
+ case WPA_CIPHER_GCMP:
+ group = "gcmp";
+ break;
case WPA_CIPHER_WEP104:
group = "wep104";
break;
@@ -3214,6 +3257,8 @@
pairwise[n++] = "tkip";
if (ie_data->pairwise_cipher & WPA_CIPHER_CCMP)
pairwise[n++] = "ccmp";
+ if (ie_data->pairwise_cipher & WPA_CIPHER_GCMP)
+ pairwise[n++] = "gcmp";
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Pairwise",
pairwise, n))
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index cff218f..178a76b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -94,6 +94,9 @@
DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_reassociate(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_remove_network(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index f4541f7..30e0eb3 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -127,7 +127,7 @@
}
wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
- NULL);
+ NULL, 0);
os_free(req_dev_types);
return reply;
@@ -346,13 +346,13 @@
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
- } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0))
goto inv_args;
out:
@@ -504,7 +504,7 @@
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, -1, 0);
+ go_intent, freq, -1, 0, 0);
if (new_pin >= 0) {
char npin[9];
@@ -630,7 +630,7 @@
if (ssid == NULL || ssid->disabled != 2)
goto err;
- if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
@@ -1049,7 +1049,7 @@
* Now construct the peer object paths in a form suitable for
* array_property_getter helper below.
*/
- peer_obj_paths = os_zalloc(num * sizeof(char *));
+ peer_obj_paths = os_calloc(num, sizeof(char *));
if (!peer_obj_paths) {
out_of_mem = 1;
@@ -1509,7 +1509,7 @@
if (network_is_persistent_group(ssid))
num++;
- paths = os_zalloc(num * sizeof(char *));
+ paths = os_calloc(num, sizeof(char *));
if (!paths) {
dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
return FALSE;
@@ -1816,7 +1816,7 @@
num_members = p2p_get_group_num_members(wpa_s->p2p_group);
- paths = os_zalloc(num_members * sizeof(char *));
+ paths = os_calloc(num_members, sizeof(char *));
if (!paths)
goto out_of_memory;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index fe1401f..711b407 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -232,6 +232,7 @@
# unix = UNIX domain sockets (default for Linux/*BSD)
# udp = UDP sockets using localhost (127.0.0.1)
# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
# y = use default (backwards compatibility)
# If this option is commented out, control interface is not included in the
# build.
@@ -505,10 +506,18 @@
# Autoscan
# This can be used to enable automatic scan support in wpa_supplicant.
-# See wpa_supplicant.conf for more information on autoscan usage.
+# See wpa_supplicant.conf for more information on autoscan usage.
#
# Enabling directly a module will enable autoscan support.
# For exponential module:
#CONFIG_AUTOSCAN_EXPONENTIAL=y
# For periodic module:
#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 82a7bcb..bc148ca 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -467,7 +467,8 @@
struct hostap_sta_driver_data *sta)
{
if (wpa_s->driver->read_sta_data)
- return wpa_s->driver->read_sta_data(wpa_s->drv_priv, sta, wpa_s->bssid);
+ return wpa_s->driver->read_sta_data(wpa_s->drv_priv, sta,
+ wpa_s->bssid);
return -1;
}
@@ -698,4 +699,14 @@
return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
}
+static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
+ enum wnm_oper oper, const u8 *peer,
+ u8 *buf, u16 *buf_len)
+{
+ if (!wpa_s->driver->wnm_oper)
+ return -1;
+ return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
+ buf_len);
+}
+
#endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index c220aec..d1eb4ff 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -35,6 +35,11 @@
ret = eap_peer_tls_register();
#endif /* EAP_TLS */
+#ifdef EAP_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_peer_unauth_tls_register();
+#endif /* EAP_UNAUTH_TLS */
+
#ifdef EAP_MSCHAPv2
if (ret == 0)
ret = eap_peer_mschapv2_register();
@@ -145,6 +150,11 @@
ret = eap_server_tls_register();
#endif /* EAP_SERVER_TLS */
+#ifdef EAP_SERVER_UNAUTH_TLS
+ if (ret == 0)
+ ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
#ifdef EAP_SERVER_MSCHAPV2
if (ret == 0)
ret = eap_server_mschapv2_register();
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index e53e156..03b8c7e 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -13,6 +13,7 @@
#include <assert.h>
#include "common.h"
+#include "utils/ext_password.h"
#include "config.h"
#include "eapol_supp/eapol_supp_sm.h"
#include "eap_peer/eap.h"
@@ -55,9 +56,8 @@
struct radius_client_data *radius;
struct hostapd_radius_servers *radius_conf;
- u8 *last_eap_radius; /* last received EAP Response from Authentication
- * Server */
- size_t last_eap_radius_len;
+ /* last received EAP Response from Authentication Server */
+ struct wpabuf *last_eap_radius;
u8 authenticator_pmk[PMK_LEN];
size_t authenticator_pmk_len;
@@ -429,6 +429,37 @@
}
+static void eapol_test_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct eapol_test_data *e = ctx;
+ struct wpa_supplicant *wpa_s = e->wpa_s;
+ char *str;
+ int res;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+ id, len);
+
+ if (wpa_s->current_ssid == NULL)
+ return;
+
+ if (id == NULL) {
+ if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ "NULL", 0) < 0)
+ return;
+ } else {
+ str = os_malloc(len * 2 + 1);
+ if (str == NULL)
+ return;
+ wpa_snprintf_hex(str, len * 2 + 1, id, len);
+ res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ str, 0);
+ os_free(str);
+ if (res < 0)
+ return;
+ }
+}
+
+
static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -456,6 +487,7 @@
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
ctx->cert_cb = eapol_test_cert_cb;
ctx->cert_in_cb = 1;
+ ctx->set_anon_id = eapol_test_set_anon_id;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
@@ -488,7 +520,7 @@
struct extra_radius_attr *p, *prev;
radius_client_deinit(e->radius);
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
radius_msg_free(e->last_recv_radius);
e->last_recv_radius = NULL;
os_free(e->eap_identity);
@@ -506,6 +538,10 @@
wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
wpa_s->ctrl_iface = NULL;
}
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+
wpa_config_free(wpa_s->conf);
p = e->extra_attrs;
@@ -574,9 +610,8 @@
static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
{
- u8 *eap;
- size_t len;
- struct eap_hdr *hdr;
+ struct wpabuf *eap;
+ const struct eap_hdr *hdr;
int eap_type = -1;
char buf[64];
struct radius_msg *msg;
@@ -586,30 +621,29 @@
msg = e->last_recv_radius;
- eap = radius_msg_get_eap(msg, &len);
+ eap = radius_msg_get_eap(msg);
if (eap == NULL) {
/* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
* RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
* attribute */
wpa_printf(MSG_DEBUG, "could not extract "
"EAP-Message from RADIUS message");
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
e->last_eap_radius = NULL;
- e->last_eap_radius_len = 0;
return;
}
- if (len < sizeof(*hdr)) {
+ if (wpabuf_len(eap) < sizeof(*hdr)) {
wpa_printf(MSG_DEBUG, "too short EAP packet "
"received from authentication server");
- os_free(eap);
+ wpabuf_free(eap);
return;
}
- if (len > sizeof(*hdr))
- eap_type = eap[sizeof(*hdr)];
+ if (wpabuf_len(eap) > sizeof(*hdr))
+ eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
- hdr = (struct eap_hdr *) eap;
+ hdr = wpabuf_head(eap);
switch (hdr->code) {
case EAP_CODE_REQUEST:
os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
@@ -632,7 +666,7 @@
break;
default:
os_strlcpy(buf, "unknown EAP code", sizeof(buf));
- wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len);
+ wpa_hexdump_buf(MSG_DEBUG, "Decapsulated EAP packet", eap);
break;
}
wpa_printf(MSG_DEBUG, "decapsulated EAP packet (code=%d "
@@ -641,20 +675,21 @@
/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
- os_free(e->last_eap_radius);
+ wpabuf_free(e->last_eap_radius);
e->last_eap_radius = eap;
- e->last_eap_radius_len = len;
{
struct ieee802_1x_hdr *dot1x;
- dot1x = os_malloc(sizeof(*dot1x) + len);
+ dot1x = os_malloc(sizeof(*dot1x) + wpabuf_len(eap));
assert(dot1x != NULL);
dot1x->version = EAPOL_VERSION;
dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
- dot1x->length = htons(len);
- os_memcpy((u8 *) (dot1x + 1), eap, len);
+ dot1x->length = htons(wpabuf_len(eap));
+ os_memcpy((u8 *) (dot1x + 1), wpabuf_head(eap),
+ wpabuf_len(eap));
eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
- (u8 *) dot1x, sizeof(*dot1x) + len);
+ (u8 *) dot1x,
+ sizeof(*dot1x) + wpabuf_len(eap));
os_free(dot1x);
}
}
@@ -1228,6 +1263,9 @@
if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
return -1;
+ if (wpas_init_ext_pw(&wpa_s) < 0)
+ return -1;
+
if (wait_for_monitor)
wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 451bfd4..bb870c0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -23,6 +23,7 @@
#include "eap_peer/eap.h"
#include "ap/hostapd.h"
#include "p2p/p2p.h"
+#include "wnm_sta.h"
#include "notify.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
@@ -40,11 +41,31 @@
#include "bss.h"
#include "scan.h"
#include "offchannel.h"
+#include "interworking.h"
+
+
+static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ struct os_time now;
+
+ if (ssid == NULL || ssid->disabled_until.sec == 0)
+ return 0;
+
+ os_get_time(&now);
+ if (ssid->disabled_until.sec > now.sec)
+ return ssid->disabled_until.sec - now.sec;
+
+ wpas_clear_temp_disabled(wpa_s, ssid, 0);
+
+ return 0;
+}
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *ssid, *old_ssid;
+ int res;
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
return 0;
@@ -63,6 +84,13 @@
return -1;
}
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
+ "disabled for %d second(s)", res);
+ return -1;
+ }
+
wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
"current AP");
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
@@ -148,6 +176,8 @@
if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
wpa_s->ap_ies_from_associnfo = 0;
+ wpa_s->current_ssid = NULL;
+ wpa_s->key_mgmt = 0;
}
@@ -450,6 +480,12 @@
return 1;
}
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
+ !rsn_ie) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " allow for non-WPA IEEE 802.1X");
+ return 1;
+ }
+
if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - no WPA/RSN proto match");
@@ -648,12 +684,20 @@
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
+ int res;
if (wpas_network_disabled(wpa_s, ssid)) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
continue;
}
+ res = wpas_temp_disabled(wpa_s, ssid);
+ if (res > 0) {
+ wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
+ "temporarily for %d second(s)", res);
+ continue;
+ }
+
#ifdef CONFIG_WPS
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
@@ -1018,6 +1062,9 @@
struct wpa_ssid *ssid = NULL;
struct wpa_scan_results *scan_res;
int ap = 0;
+#ifndef CONFIG_NO_RANDOM_POOL
+ size_t i, num;
+#endif /* CONFIG_NO_RANDOM_POOL */
#ifdef CONFIG_AP
if (wpa_s->ap_iface)
@@ -1032,7 +1079,7 @@
#else
if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
#endif
- wpa_s->global->p2p != NULL) {
+ wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending) {
wpa_s->p2p_cb_on_scan_complete = 0;
if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
@@ -1040,6 +1087,7 @@
return -1;
}
}
+ wpa_s->sta_scan_pending = 0;
#endif /* CONFIG_P2P */
scan_res = wpa_supplicant_get_scan_results(wpa_s,
@@ -1055,7 +1103,6 @@
}
#ifndef CONFIG_NO_RANDOM_POOL
- size_t i, num;
num = scan_res->num;
if (num > 10)
num = 10;
@@ -1134,6 +1181,8 @@
return 0;
}
+ wpas_wps_update_ap_info(wpa_s, scan_res);
+
selected = wpa_supplicant_pick_network(wpa_s, scan_res, &ssid);
if (selected) {
@@ -1178,6 +1227,19 @@
return 0;
}
#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+ if (wpa_s->conf->auto_interworking &&
+ wpa_s->conf->interworking &&
+ wpa_s->conf->cred) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: "
+ "start ANQP fetch since no matching "
+ "networks found");
+ wpa_s->network_select = 1;
+ wpa_s->auto_network_select = 1;
+ interworking_start_fetch_anqp(wpa_s);
+ return 0;
+ }
+#endif /* CONFIG_INTERWORKING */
if (wpa_supplicant_req_sched_scan(wpa_s))
wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
timeout_usec);
@@ -1548,7 +1610,6 @@
{
u8 bssid[ETH_ALEN];
int ft_completed;
- int bssid_changed;
struct wpa_driver_capa capa;
#ifdef CONFIG_AP
@@ -1566,17 +1627,21 @@
if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
return;
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
+ wpa_supplicant_disassociate(
+ wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+ return;
+ }
+
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
- if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
- os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
random_add_randomness(bssid, ETH_ALEN);
- bssid_changed = os_memcmp(wpa_s->bssid, bssid, ETH_ALEN);
os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
- if (bssid_changed)
- wpas_notify_bssid_changed(wpa_s);
+ wpas_notify_bssid_changed(wpa_s);
if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
wpa_clear_keys(wpa_s, bssid);
@@ -1728,6 +1793,8 @@
ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
}
#endif /* CONFIG_IBSS_RSN */
+
+ wpas_wps_notify_assoc(wpa_s, bssid);
}
@@ -1744,10 +1811,40 @@
int locally_generated)
{
const u8 *bssid;
+
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+ /*
+ * At least Host AP driver and a Prism3 card seemed to be
+ * generating streams of disconnected events when configuring
+ * IBSS for WPA-None. Ignore them for now.
+ */
+ return;
+ }
+
+ bssid = wpa_s->bssid;
+ if (is_zero_ether_addr(bssid))
+ bssid = wpa_s->pending_bssid;
+
+ if (!is_zero_ether_addr(bssid) ||
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+ " reason=%d%s",
+ MAC2STR(bssid), reason_code,
+ locally_generated ? " locally_generated=1" : "");
+ }
+}
+
+
+static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
+ u16 reason_code,
+ int locally_generated)
+{
+ const u8 *bssid;
int authenticating;
u8 prev_pending_bssid[ETH_ALEN];
struct wpa_bss *fast_reconnect = NULL;
struct wpa_ssid *fast_reconnect_ssid = NULL;
+ struct wpa_ssid *last_ssid;
authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -1767,6 +1864,7 @@
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
"pre-shared key may be incorrect");
+ wpas_auth_failed(wpa_s);
}
if (!wpa_s->auto_reconnect_disabled ||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
@@ -1814,22 +1912,18 @@
else
wpa_s->disconnect_reason = reason_code;
wpas_notify_disconnect_reason(wpa_s);
- if (!is_zero_ether_addr(bssid) ||
- wpa_s->wpa_state >= WPA_AUTHENTICATING) {
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
- " reason=%d%s",
- MAC2STR(bssid), reason_code,
- locally_generated ? " locally_generated=1" : "");
- }
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
wpa_s->keys_cleared = 0;
wpa_clear_keys(wpa_s, wpa_s->bssid);
}
+ last_ssid = wpa_s->current_ssid;
wpa_supplicant_mark_disassoc(wpa_s);
- if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+ if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
+ wpa_s->current_ssid = last_ssid;
+ }
if (fast_reconnect) {
#ifndef CONFIG_NO_SCAN_PROCESSING
@@ -2037,6 +2131,25 @@
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_IEEE80211V
+static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (data == NULL)
+ return;
+ switch (data->wnm.oper) {
+ case WNM_OPER_SLEEP:
+ wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request "
+ "(action=%d, intval=%d)",
+ data->wnm.sleep_action, data->wnm.sleep_intval);
+ ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action,
+ data->wnm.sleep_intval);
+ break;
+ }
+}
+#endif /* CONFIG_IEEE80211V */
+
+
#ifdef CONFIG_IEEE80211R
static void
wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
@@ -2323,15 +2436,30 @@
#endif /* CONFIG_AP */
wpa_supplicant_event_disassoc(wpa_s, reason_code,
locally_generated);
+ if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+ ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+ (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+ eapol_sm_failed(wpa_s->eapol)))
+ wpas_auth_failed(wpa_s);
#ifdef CONFIG_P2P
if (event == EVENT_DEAUTH && data) {
- wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr,
- reason_code,
- data->deauth_info.ie,
- data->deauth_info.ie_len,
- locally_generated);
+ if (wpas_p2p_deauth_notif(wpa_s,
+ data->deauth_info.addr,
+ reason_code,
+ data->deauth_info.ie,
+ data->deauth_info.ie_len,
+ locally_generated) > 0) {
+ /*
+ * The interface was removed, so cannot
+ * continue processing any additional
+ * operations after this.
+ */
+ break;
+ }
}
#endif /* CONFIG_P2P */
+ wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
+ locally_generated);
break;
case EVENT_MICHAEL_MIC_FAILURE:
wpa_supplicant_event_michael_mic_failure(wpa_s, data);
@@ -2339,6 +2467,18 @@
#ifndef CONFIG_NO_SCAN_PROCESSING
case EVENT_SCAN_RESULTS:
wpa_supplicant_event_scan_results(wpa_s, data);
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL &&
+ wpa_s->wpa_state != WPA_AUTHENTICATING &&
+ wpa_s->wpa_state != WPA_ASSOCIATING) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after scan result processing");
+ }
+ }
+#endif /* CONFIG_P2P */
break;
#endif /* CONFIG_NO_SCAN_PROCESSING */
case EVENT_ASSOCINFO:
@@ -2360,6 +2500,11 @@
wpa_supplicant_event_tdls(wpa_s, data);
break;
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_IEEE80211V
+ case EVENT_WNM:
+ wpa_supplicant_event_wnm(wpa_s, data);
+ break;
+#endif /* CONFIG_IEEE80211V */
#ifdef CONFIG_IEEE80211R
case EVENT_FT_RESPONSE:
wpa_supplicant_event_ft_response(wpa_s, data);
@@ -2585,6 +2730,12 @@
}
#endif /* CONFIG_SME */
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211V
+ if (data->rx_action.category == WLAN_ACTION_WNM) {
+ ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
+ break;
+ }
+#endif /* CONFIG_IEEE80211V */
#ifdef CONFIG_GAS
if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
gas_query_rx(wpa_s->gas, data->rx_action.da,
diff --git a/wpa_supplicant/examples/p2p/p2p_connect.py b/wpa_supplicant/examples/p2p/p2p_connect.py
new file mode 100644
index 0000000..59b0a9d
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_connect.py
@@ -0,0 +1,299 @@
+#!/usr/bin/python
+# Tests p2p_connect
+# Will try to connect to another peer
+# and form a group
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> -m <wps_method> \ " \
+ % sys.argv[0]
+ print " -a <addr> [-p <pin>] [-g <go_intent>] \ "
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -m = wps method"
+ print " -a = peer address"
+ print " -p = pin number (8 digits)"
+ print " -g = group owner intent"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0 -a 0015008352c0 -m display -p 12345670" % sys.argv[0]
+
+
+# Required Signals
+def GONegotiationSuccess(status):
+ print "Go Negotiation Success"
+
+def GONegotiationFailure(status):
+ print 'Go Negotiation Failed. Status:'
+ print format(status)
+ os._exit(0)
+
+def GroupStarted(properties):
+ if properties.has_key("group_object"):
+ print 'Group Formation Complete %s' \
+ % properties["group_object"]
+ os._exit(0)
+
+def WpsFailure(status, etc):
+ print "WPS Authentication Failure".format(status)
+ print etc
+ os._exit(0)
+
+class P2P_Connect():
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global ifname
+ global wpas
+ global wpas_dbus_interface
+ global timeout
+ global path
+ global wps_method
+ global go_intent
+ global addr
+ global pin
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Dictionary of Arguements
+ global p2p_connect_arguements
+
+ # Constructor
+ def __init__(self,ifname,wpas_dbus_interface,addr,
+ pin,wps_method,go_intent):
+ # Initializes variables and threads
+ self.ifname = ifname
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.wps_method = wps_method
+ self.go_intent = go_intent
+ self.addr = addr
+ self.pin = pin
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = \
+ "/" + self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = \
+ self.wpas_dbus_opath + "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(
+ self.wpas_object, self.wpas_dbus_interface)
+
+ # See if wpa_supplicant already knows about this interface
+ self.path = None
+ try:
+ self.path = self.wpas.GetInterface(ifname)
+ except:
+ if not str(exc).startswith(
+ self.wpas_dbus_interface + \
+ ".InterfaceUnknown:"):
+ raise exc
+ try:
+ path = self.wpas.CreateInterface(
+ {'Ifname': ifname, 'Driver': 'test'})
+ time.sleep(1)
+
+ except dbus.DBusException, exc:
+ if not str(exc).startswith(
+ self.wpas_dbus_interface + \
+ ".InterfaceExists:"):
+ raise exc
+
+ # Get Interface and objects
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface,self.path)
+ self.p2p_interface = dbus.Interface(
+ self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Add signals
+ self.bus.add_signal_receiver(GONegotiationSuccess,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GONegotiationSuccess")
+ self.bus.add_signal_receiver(GONegotiationFailure,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GONegotiationFailure")
+ self.bus.add_signal_receiver(GroupStarted,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GroupStarted")
+ self.bus.add_signal_receiver(WpsFailure,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="WpsFailed")
+
+
+ #Constructing all the arguements needed to connect
+ def constructArguements(self):
+ # Adding required arguements
+ self.p2p_connect_arguements = {'wps_method':self.wps_method,
+ 'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
+
+ # Display requires a pin, and a go intent of 15
+ if (self.wps_method == 'display'):
+ if (self.pin != None):
+ self.p2p_connect_arguements.update({'pin':self.pin})
+ else:
+ print "Error:\n Pin required for wps_method=display"
+ usage()
+ quit()
+
+ if (self.go_intent != None and int(self.go_intent) != 15):
+ print "go_intent overwritten to 15"
+
+ self.go_intent = '15'
+
+ # Keypad requires a pin, and a go intent of less than 15
+ elif (self.wps_method == 'keypad'):
+ if (self.pin != None):
+ self.p2p_connect_arguements.update({'pin':self.pin})
+ else:
+ print "Error:\n Pin required for wps_method=keypad"
+ usage()
+ quit()
+
+ if (self.go_intent != None and int(self.go_intent) == 15):
+ error = "Error :\n Group Owner intent cannot be" + \
+ " 15 for wps_method=keypad"
+ print error
+ usage()
+ quit()
+
+ # Doesn't require pin
+ # for ./wpa_cli, p2p_connect [mac] [pin#], wps_method=keypad
+ elif (self.wps_method == 'pin'):
+ if (self.pin != None):
+ print "pin ignored"
+
+ # No pin is required for pbc so it is ignored
+ elif (self.wps_method == 'pbc'):
+ if (self.pin != None):
+ print "pin ignored"
+
+ else:
+ print "Error:\n wps_method not supported or does not exist"
+ usage()
+ quit()
+
+ # Go_intent is optional for all arguements
+ if (self.go_intent != None):
+ self.p2p_connect_arguements.update(
+ {'go_intent':dbus.Int32(self.go_intent)})
+
+ # Running p2p_connect
+ def run(self):
+ try:
+ result_pin = self.p2p_interface.Connect(
+ self.p2p_connect_arguements)
+
+ except dbus.DBusException, exc:
+ raise exc
+
+ if (self.wps_method == 'pin' and \
+ not self.p2p_connect_arguements.has_key('pin') ):
+ print "Connect return with pin value of %d " % int(result_pin)
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+ # Required
+ interface_name = None
+ wps_method = None
+ addr = None
+
+ # Conditionally optional
+ pin = None
+
+ # Optional
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+ go_intent = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:m:a:p:g:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # WPS Method
+ elif (key == "-m"):
+ wps_method = value
+ # Address
+ elif (key == "-a"):
+ addr = value
+ # Pin
+ elif (key == "-p"):
+ pin = value
+ # Group Owner Intent
+ elif (key == "-g"):
+ go_intent = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Required Arguements check
+ if (interface_name == None or wps_method == None or addr == None):
+ print "Error:\n Required arguements not specified"
+ usage()
+ quit()
+
+ # Group Owner Intent Check
+ if (go_intent != None and (int(go_intent) > 15 or int(go_intent) < 0) ):
+ print "Error:\n Group Owner Intent must be between 0 and 15 inclusive"
+ usage()
+ quit()
+
+ # Pin Check
+ if (pin != None and len(pin) != 8):
+ print "Error:\n Pin is not 8 digits"
+ usage()
+ quit()
+
+ try:
+ p2p_connect_test = P2P_Connect(interface_name,wpas_dbus_interface,
+ addr,pin,wps_method,go_intent)
+
+ except:
+ print "Error:\n Invalid Arguements"
+ usage()
+ quit()
+
+ p2p_connect_test.constructArguements()
+ p2p_connect_test.run()
+
+ os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_disconnect.py b/wpa_supplicant/examples/p2p/p2p_disconnect.py
new file mode 100644
index 0000000..c3e39b3
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_disconnect.py
@@ -0,0 +1,169 @@
+#!/usr/bin/python
+# Tests P2P_Disconnect
+# Will perform disconnect on interface_name
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i p2p-wlan0-0" % sys.argv[0]
+
+# Required Signals
+def GroupFinished(status, etc):
+ print "Disconnected"
+ os._exit(0)
+
+class P2P_Disconnect (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(GroupFinished,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GroupFinished")
+
+ # Runs p2p_disconnect
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.Disconnect()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_disconnect_test = P2P_Disconnect(interface_name,
+ wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Disconnect
+ p2p_disconnect_test.start()
+
+ try:
+ time.sleep(int(p2p_disconnect_test.timeout))
+
+ except:
+ pass
+
+ print "Disconnect timed out"
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_find.py b/wpa_supplicant/examples/p2p/p2p_find.py
new file mode 100644
index 0000000..973d46a
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_find.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python
+# Tests p2p_find
+# Will list all devices found/lost within a time frame (timeout)
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -t = timeout = 0s (infinite)"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0 -t 10" % sys.argv[0]
+
+# Required Signals
+def deviceFound(devicepath):
+ print "Device found: %s" % (devicepath)
+
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+class P2P_Find (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global timeout
+ global path
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.timeout = int(timeout)
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ #Adds listeners for find and lost
+ self.bus.add_signal_receiver(deviceFound,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceFound")
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+
+
+ # Sets up p2p_find
+ P2PFindDict = dbus.Dictionary(
+ {'Timeout':int(self.timeout)})
+ self.p2p_interface.Find(P2PFindDict)
+
+ # Run p2p_find
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+ # Defaults for optional inputs
+ timeout = 0
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:t:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Timeout
+ elif (key == "-t"):
+ if ( int(value) >= 0):
+ timeout = value
+ else:
+ print "Error:\n Timeout cannot be negative"
+ usage()
+ quit()
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_find_test = P2P_Find(interface_name, wpas_dbus_interface, timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_find_test.start()
+
+ try:
+ # If timeout is 0, then run forever
+ if (timeout == 0):
+ while(True):
+ pass
+ # Else sleep for (timeout)
+ else:
+ time.sleep(p2p_find_test.timeout)
+
+ except:
+ pass
+
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_flush.py b/wpa_supplicant/examples/p2p/p2p_flush.py
new file mode 100644
index 0000000..ff8509d
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_flush.py
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# Tests P2P_Flush
+# Will flush the p2p interface
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals\
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+class P2P_Flush (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+
+ # Runs p2p_flush
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.Flush()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+ # Needed to show which devices were lost
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_flush_test = P2P_Flush(interface_name, wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_flush_test.start()
+
+ try:
+ time.sleep(int(p2p_flush_test.timeout))
+
+ except:
+ pass
+
+ print "p2p_flush complete"
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_group_add.py b/wpa_supplicant/examples/p2p/p2p_group_add.py
new file mode 100644
index 0000000..5c8fdaf
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_group_add.py
@@ -0,0 +1,222 @@
+#!/usr/bin/python
+# Tests p2p_group_add
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+import threading
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> [-p <persistent>] \ " \
+ % sys.argv[0]
+ print " [-f <frequency>] [-o <group_object_path>] \ "
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -p = persistant group = 0 (0=false, 1=true)"
+ print " -f = frequency"
+ print " -o = persistent group object path"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def GroupStarted(properties):
+ if properties.has_key("group_object"):
+ print 'Group Formation Complete %s' \
+ % properties["group_object"]
+ os._exit(0)
+
+def WpsFailure(status, etc):
+ print "WPS Authentication Failure".format(status)
+ print etc
+ os._exit(0)
+
+class P2P_Group_Add (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global persistent
+ global frequency
+ global persistent_group_object
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Arguements
+ global P2PDictionary
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,persistent,frequency,
+ persistent_group_object):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.persistent = persistent
+ self.frequency = frequency
+ self.persistent_group_object = persistent_group_object
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ #Adds listeners
+ self.bus.add_signal_receiver(GroupStarted,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="GroupStarted")
+ self.bus.add_signal_receiver(WpsFailure,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="WpsFailed")
+
+ # Sets up p2p_group_add dictionary
+ def constructArguements(self):
+ self.P2PDictionary = {'persistent':self.persistent}
+
+ if (self.frequency != None):
+ if (int(self.frequency) > 0):
+ self.P2PDictionary.update({'frequency':int(self.frequency)})
+ else:
+ print "Error:\n Frequency must be greater than 0"
+ usage()
+ os._exit(0)
+
+ if (self.persistent_group_object != None):
+ self.P2PDictionary.update({'persistent_group_object':
+ self.persistent_group_object})
+
+ # Run p2p_group_remove
+ def run(self):
+ try:
+ self.p2p_interface.GroupAdd(self.P2PDictionary)
+
+ except:
+ print "Error:\n Could not preform group add"
+ usage()
+ os._exit(0)
+
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+
+ # Defaults for optional inputs
+ # 0 = false, 1 = true
+ persistent = False
+ frequency = None
+ persistent_group_object = None
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:p:f:o:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Timeout
+ elif (key == "-p"):
+ if (value == '0'):
+ persistent = False
+ elif (value == '1'):
+ persistent = True
+ else:
+ print "Error:\n Persistent can only be 1 or 0"
+ usage()
+ os._exit(0)
+ # Frequency
+ elif (key == "-f"):
+ frequency = value
+ # Persistent group object path
+ elif (key == "-o"):
+ persistent_group_object = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ try:
+ p2p_group_add_test = P2P_Group_Add(interface_name,wpas_dbus_interface,
+ persistent,frequency,persistent_group_object)
+ except:
+ print "Error:\n Invalid Arguements"
+
+ p2p_group_add_test.constructArguements()
+ p2p_group_add_test.start()
+ time.sleep(5)
+ print "Error:\n Group formation timed out"
+ os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_invite.py b/wpa_supplicant/examples/p2p/p2p_invite.py
new file mode 100644
index 0000000..6deb397
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_invite.py
@@ -0,0 +1,201 @@
+#!/usr/bin/python
+# Tests p2p_invite
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import getopt
+import threading
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> -a <addr> \ " \
+ % sys.argv[0]
+ print " [-o <persistent_group_object>] [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -a = address of peer"
+ print " -o = persistent group object path"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i p2p-wlan0-0 -a 00150083523c" % sys.argv[0]
+
+# Required Signals
+def InvitationResult(invite_result):
+ print "Inviation Result signal :"
+ status = invite_result['status']
+ print "status = ", status
+ if invite_result.has_key('BSSID'):
+ bssid = invite_result['BSSID']
+ print "BSSID = ", hex(bssid[0]) , ":" , \
+ hex(bssid[1]) , ":" , hex(bssid[2]) , ":", \
+ hex(bssid[3]) , ":" , hex(bssid[4]) , ":" , \
+ hex(bssid[5])
+ os._exit(0)
+
+class P2P_Invite (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global addr
+ global persistent_group_object
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Arguements
+ global P2PDictionary
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,addr,
+ persistent_group_object):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.addr = addr
+ self.persistent_group_object = persistent_group_object
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ #Adds listeners
+ self.bus.add_signal_receiver(InvitationResult,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="InvitationResult")
+
+ # Sets up p2p_invite dictionary
+ def constructArguements(self):
+ self.P2PDictionary = \
+ {'peer':dbus.ObjectPath(self.path+'/Peers/'+self.addr)}
+ if (self.persistent_group_object != None):
+ self.P2PDictionary.update({"persistent_group_object":
+ self.persistent_group_object})
+
+ # Run p2p_invite
+ def run(self):
+ try:
+ self.p2p_interface.Invite(self.P2PDictionary)
+
+ except:
+ print "Error:\n Invalid Arguements"
+ usage()
+ os._exit(0)
+
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+ # Defaults for optional inputs
+ addr = None
+ persistent_group_object = None
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:o:w:a:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ elif (key == "-a"):
+ addr = value
+ # Persistent group object path
+ elif (key == "-o"):
+ persistent_group_object = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ if (addr == None):
+ print "Error:\n peer address is required"
+ usage()
+ quit()
+
+ try:
+ p2p_invite_test = \
+ P2P_Invite(interface_name,wpas_dbus_interface,
+ addr,persistent_group_object)
+ except:
+ print "Error:\n Invalid Arguements"
+ usage()
+ os._exit(1)
+
+ p2p_invite_test.constructArguements()
+ p2p_invite_test.start()
+ time.sleep(10)
+ print "Error:\n p2p_invite timed out"
+ os._exit(0)
diff --git a/wpa_supplicant/examples/p2p/p2p_listen.py b/wpa_supplicant/examples/p2p/p2p_listen.py
new file mode 100644
index 0000000..bb3c1e4
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_listen.py
@@ -0,0 +1,182 @@
+#!/usr/bin/python
+# Tests P2P_Find
+# Will listen
+# Then Program will exit
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> [-t <timeout>] \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -t = timeout = 0s (infinite)"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0 -t 5" % sys.argv[0]
+
+# Required Signals
+def p2pStateChange(status):
+ print status
+
+class P2P_Listen(threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.timeout = int(timeout)
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ self.bus.add_signal_receiver(p2pStateChange,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="P2PStateChanged")
+
+ # Run p2p_find
+ def run(self):
+ # Sets up p2p_listen
+ self.p2p_interface.Listen(int(self.timeout))
+
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ gobject.MainLoop().run()
+
+if __name__ == "__main__":
+
+ # Defaults for optional inputs
+ timeout = 0
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"hi:t:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Timeout
+ elif (key == "-t"):
+ if ( int(value) >= 0):
+ timeout = value
+ else:
+ print "Error:\n Timeout cannot be negative"
+ usage()
+ quit()
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_listen_test = P2P_Listen(interface_name, wpas_dbus_interface, timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_listen_test.start()
+
+ try:
+ # If timeout is 0, then run forever
+ if (int(p2p_listen_test.timeout) == 0):
+ while(True):
+ pass
+ # Else sleep for (timeout)
+ else:
+ time.sleep(int(p2p_listen_test.timeout))
+
+ except:
+ pass
+
+ quit()
diff --git a/wpa_supplicant/examples/p2p/p2p_stop_find.py b/wpa_supplicant/examples/p2p/p2p_stop_find.py
new file mode 100644
index 0000000..f6c03b0
--- /dev/null
+++ b/wpa_supplicant/examples/p2p/p2p_stop_find.py
@@ -0,0 +1,174 @@
+#!/usr/bin/python
+# Tests p2p_stop_find
+######### MAY NEED TO RUN AS SUDO #############
+
+import dbus
+import sys, os
+import time
+import gobject
+import threading
+import getopt
+from dbus.mainloop.glib import DBusGMainLoop
+
+def usage():
+ print "Usage:"
+ print " %s -i <interface_name> \ " \
+ % sys.argv[0]
+ print " [-w <wpas_dbus_interface>]"
+ print "Options:"
+ print " -i = interface name"
+ print " -w = wpas dbus interface = fi.w1.wpa_supplicant1"
+ print "Example:"
+ print " %s -i wlan0" % sys.argv[0]
+
+# Required Signals
+def deviceLost(devicepath):
+ print "Device lost: %s" % (devicepath)
+
+def p2pStateChange(status):
+ print status
+ os._exit(0)
+
+class P2P_Stop_Find (threading.Thread):
+ # Needed Variables
+ global bus
+ global wpas_object
+ global interface_object
+ global p2p_interface
+ global interface_name
+ global wpas
+ global wpas_dbus_interface
+ global path
+ global timeout
+
+ # Dbus Paths
+ global wpas_dbus_opath
+ global wpas_dbus_interfaces_opath
+ global wpas_dbus_interfaces_interface
+ global wpas_dbus_interfaces_p2pdevice
+
+ # Constructor
+ def __init__(self,interface_name,wpas_dbus_interface,timeout):
+ # Initializes variables and threads
+ self.interface_name = interface_name
+ self.wpas_dbus_interface = wpas_dbus_interface
+ self.timeout = timeout
+
+ # Initializes thread and daemon allows for ctrl-c kill
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ # Generating interface/object paths
+ self.wpas_dbus_opath = "/" + \
+ self.wpas_dbus_interface.replace(".","/")
+ self.wpas_wpas_dbus_interfaces_opath = self.wpas_dbus_opath + \
+ "/Interfaces"
+ self.wpas_dbus_interfaces_interface = \
+ self.wpas_dbus_interface + ".Interface"
+ self.wpas_dbus_interfaces_p2pdevice = \
+ self.wpas_dbus_interfaces_interface \
+ + ".P2PDevice"
+
+ # Getting interfaces and objects
+ DBusGMainLoop(set_as_default=True)
+ self.bus = dbus.SystemBus()
+ self.wpas_object = self.bus.get_object(
+ self.wpas_dbus_interface,
+ self.wpas_dbus_opath)
+ self.wpas = dbus.Interface(self.wpas_object,
+ self.wpas_dbus_interface)
+
+ # Try to see if supplicant knows about interface
+ # If not, throw an exception
+ try:
+ self.path = self.wpas.GetInterface(
+ self.interface_name)
+ except dbus.DBusException, exc:
+ error = 'Error:\n Interface ' + self.interface_name \
+ + ' was not found'
+ print error
+ usage()
+ os._exit(0)
+
+ self.interface_object = self.bus.get_object(
+ self.wpas_dbus_interface, self.path)
+ self.p2p_interface = dbus.Interface(self.interface_object,
+ self.wpas_dbus_interfaces_p2pdevice)
+
+ # Signals
+ self.bus.add_signal_receiver(deviceLost,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="DeviceLost")
+ self.bus.add_signal_receiver(p2pStateChange,
+ dbus_interface=self.wpas_dbus_interfaces_p2pdevice,
+ signal_name="P2PStateChanged")
+
+ # Runs p2p_stop_find
+ def run(self):
+ # Allows other threads to keep working while MainLoop runs
+ # Required for timeout implementation
+ gobject.MainLoop().get_context().iteration(True)
+ gobject.threads_init()
+ self.p2p_interface.StopFind()
+ gobject.MainLoop().run()
+
+
+if __name__ == "__main__":
+ # Needed because P2PStateChanged signal is not caught
+ timeout = 5
+ # Defaults for optional inputs
+ wpas_dbus_interface = 'fi.w1.wpa_supplicant1'
+
+ # interface_name is required
+ interface_name = None
+
+ # Using getopts to handle options
+ try:
+ options, args = getopt.getopt(sys.argv[1:],"ht:i:w:")
+
+ except getopt.GetoptError:
+ usage()
+ quit()
+
+ # If theres a switch, override default option
+ for key, value in options:
+ # Help
+ if (key == "-h"):
+ usage()
+ quit()
+ # Interface Name
+ elif (key == "-i"):
+ interface_name = value
+ # Dbus interface
+ elif (key == "-w"):
+ wpas_dbus_interface = value
+ else:
+ assert False, "unhandled option"
+
+ # Interface name is required and was not given
+ if (interface_name == None):
+ print "Error:\n interface_name is required"
+ usage()
+ quit()
+
+ # Constructor
+ try:
+ p2p_stop_find_test = P2P_Stop_Find(interface_name,
+ wpas_dbus_interface,timeout)
+
+ except:
+ print "Error:\n Invalid wpas_dbus_interface"
+ usage()
+ quit()
+
+ # Start P2P_Find
+ p2p_stop_find_test.start()
+
+ try:
+ time.sleep(int(p2p_stop_find_test.timeout))
+
+ except:
+ pass
+
+ print "p2p find stopped"
+ quit()
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 1fd6e00..efa9be8 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -19,7 +19,7 @@
#include "gas_query.h"
-#define GAS_QUERY_TIMEOUT 5
+#define GAS_QUERY_TIMEOUT_PERIOD 5
struct gas_query_pending {
@@ -457,7 +457,7 @@
return -1;
}
- eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout,
+ eloop_register_timeout(GAS_QUERY_TIMEOUT_PERIOD, 0, gas_query_timeout,
gas, query);
return dialog_token;
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 2afa16c..0eb6119 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -110,10 +110,14 @@
const u8 *pos = data;
u8 subtype;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+ struct wpa_bss_anqp *anqp = NULL;
if (slen < 2)
return;
+ if (bss)
+ anqp = bss->anqp;
+
subtype = *pos++;
slen--;
@@ -130,9 +134,9 @@
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Operator Friendly Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_operator_friendly_name);
- bss->hs20_operator_friendly_name =
+ if (anqp) {
+ wpabuf_free(anqp->hs20_operator_friendly_name);
+ anqp->hs20_operator_friendly_name =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -140,18 +144,18 @@
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" WAN Metrics", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "WAN Metrics", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_wan_metrics);
- bss->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->hs20_wan_metrics);
+ anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen);
}
break;
case HS20_STYPE_CONNECTION_CAPABILITY:
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Connection Capability", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_connection_capability);
- bss->hs20_connection_capability =
+ if (anqp) {
+ wpabuf_free(anqp->hs20_connection_capability);
+ anqp->hs20_connection_capability =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -159,9 +163,9 @@
wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
" Operating Class", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
- if (bss) {
- wpabuf_free(bss->hs20_operating_class);
- bss->hs20_operating_class =
+ if (anqp) {
+ wpabuf_free(anqp->hs20_operating_class);
+ anqp->hs20_operating_class =
wpabuf_alloc_copy(pos, slen);
}
break;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 515d94b..b362bcb 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -15,6 +15,7 @@
#include "utils/pcsc_funcs.h"
#include "drivers/driver.h"
#include "eap_common/eap_defs.h"
+#include "eap_peer/eap.h"
#include "eap_peer/eap_methods.h"
#include "wpa_supplicant_i.h"
#include "config.h"
@@ -51,6 +52,18 @@
}
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+
+ if (wpa_s->last_scan_res_used > 0) {
+ struct os_time now;
+ os_get_time(&now);
+ if (now.sec - wpa_s->last_scan.sec <= 5) {
+ wpa_printf(MSG_DEBUG, "Interworking: Old scan results "
+ "are fresh - connect without new scan");
+ if (wpas_select_network_from_last_scan(wpa_s) == 0)
+ return;
+ }
+ }
+
wpa_supplicant_req_scan(wpa_s, 0, 0);
}
@@ -95,27 +108,101 @@
}
+static int cred_with_roaming_consortium(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->roaming_consortium_len)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_3gpp(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->pcsc || cred->imsi)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_nai_realm(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->pcsc || cred->imsi)
+ continue;
+ if (!cred->eap_method)
+ return 1;
+ if (cred->realm && cred->roaming_consortium_len == 0)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int cred_with_domain(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_cred *cred;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->domain || cred->pcsc || cred->imsi)
+ return 1;
+ }
+ return 0;
+}
+
+
+static int additional_roaming_consortiums(struct wpa_bss *bss)
+{
+ const u8 *ie;
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+ if (ie == NULL || ie[1] == 0)
+ return 0;
+ return ie[2]; /* Number of ANQP OIs */
+}
+
+
static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
struct wpabuf *buf;
int ret = 0;
int res;
- u16 info_ids[] = {
- ANQP_CAPABILITY_LIST,
- ANQP_VENUE_NAME,
- ANQP_NETWORK_AUTH_TYPE,
- ANQP_ROAMING_CONSORTIUM,
- ANQP_IP_ADDR_TYPE_AVAILABILITY,
- ANQP_NAI_REALM,
- ANQP_3GPP_CELLULAR_NETWORK,
- ANQP_DOMAIN_NAME
- };
+ u16 info_ids[8];
+ size_t num_info_ids = 0;
struct wpabuf *extra = NULL;
+ int all = wpa_s->fetch_all_anqp;
wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
MAC2STR(bss->bssid));
+ info_ids[num_info_ids++] = ANQP_CAPABILITY_LIST;
+ if (all) {
+ info_ids[num_info_ids++] = ANQP_VENUE_NAME;
+ info_ids[num_info_ids++] = ANQP_NETWORK_AUTH_TYPE;
+ }
+ if (all || (cred_with_roaming_consortium(wpa_s) &&
+ additional_roaming_consortiums(bss)))
+ info_ids[num_info_ids++] = ANQP_ROAMING_CONSORTIUM;
+ if (all)
+ info_ids[num_info_ids++] = ANQP_IP_ADDR_TYPE_AVAILABILITY;
+ if (all || cred_with_nai_realm(wpa_s))
+ info_ids[num_info_ids++] = ANQP_NAI_REALM;
+ if (all || cred_with_3gpp(wpa_s))
+ info_ids[num_info_ids++] = ANQP_3GPP_CELLULAR_NETWORK;
+ if (all || cred_with_domain(wpa_s))
+ info_ids[num_info_ids++] = ANQP_DOMAIN_NAME;
+ wpa_hexdump(MSG_DEBUG, "Interworking: ANQP Query info",
+ (u8 *) info_ids, num_info_ids * 2);
+
#ifdef CONFIG_HS20
if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
u8 *len_pos;
@@ -130,16 +217,18 @@
wpabuf_put_u8(extra, HS20_STYPE_QUERY_LIST);
wpabuf_put_u8(extra, 0); /* Reserved */
wpabuf_put_u8(extra, HS20_STYPE_CAPABILITY_LIST);
- wpabuf_put_u8(extra, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
- wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
- wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
- wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+ if (all) {
+ wpabuf_put_u8(extra,
+ HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+ wpabuf_put_u8(extra, HS20_STYPE_WAN_METRICS);
+ wpabuf_put_u8(extra, HS20_STYPE_CONNECTION_CAPABILITY);
+ wpabuf_put_u8(extra, HS20_STYPE_OPERATING_CLASS);
+ }
gas_anqp_set_element_len(extra, len_pos);
}
#endif /* CONFIG_HS20 */
- buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
- extra);
+ buf = anqp_build_req(info_ids, num_info_ids, extra);
wpabuf_free(extra);
if (buf == NULL)
return -1;
@@ -329,7 +418,7 @@
wpa_printf(MSG_DEBUG, "No room for EAP Methods");
return NULL;
}
- r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
+ r->eap = os_calloc(r->eap_count, sizeof(struct nai_realm_eap));
if (r->eap == NULL)
return NULL;
@@ -365,7 +454,7 @@
return NULL;
}
- realm = os_zalloc(num * sizeof(struct nai_realm));
+ realm = os_calloc(num, sizeof(struct nai_realm));
if (realm == NULL)
return NULL;
@@ -550,6 +639,7 @@
break;
if (os_memcmp(pos, plmn, 3) == 0)
return 1; /* Found matching PLMN */
+ pos += 3;
}
}
@@ -561,7 +651,7 @@
static int build_root_nai(char *nai, size_t nai_len, const char *imsi,
- char prefix)
+ size_t mnc_len, char prefix)
{
const char *sep, *msin;
char *end, *pos;
@@ -579,12 +669,16 @@
return -1;
}
sep = os_strchr(imsi, '-');
- if (sep == NULL)
+ if (sep) {
+ plmn_len = sep - imsi;
+ msin = sep + 1;
+ } else if (mnc_len && os_strlen(imsi) >= 3 + mnc_len) {
+ plmn_len = 3 + mnc_len;
+ msin = imsi + plmn_len;
+ } else
return -1;
- plmn_len = sep - imsi;
if (plmn_len != 5 && plmn_len != 6)
return -1;
- msin = sep + 1;
msin_len = os_strlen(msin);
pos = nai;
@@ -615,7 +709,7 @@
static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
{
char nai[100];
- if (build_root_nai(nai, sizeof(nai), imsi, prefix) < 0)
+ if (build_root_nai(nai, sizeof(nai), imsi, 0, prefix) < 0)
return -1;
return wpa_config_set_quoted(ssid, "identity", nai);
}
@@ -623,6 +717,18 @@
#endif /* INTERWORKING_3GPP */
+static int interworking_set_hs20_params(struct wpa_ssid *ssid)
+{
+ if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0) < 0)
+ return -1;
+ if (wpa_config_set(ssid, "proto", "RSN", 0) < 0)
+ return -1;
+ if (wpa_config_set(ssid, "pairwise", "CCMP", 0) < 0)
+ return -1;
+ return 0;
+}
+
+
static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
struct wpa_bss *bss)
{
@@ -630,8 +736,11 @@
struct wpa_cred *cred;
struct wpa_ssid *ssid;
const u8 *ie;
+ int eap_type;
+ int res;
+ char prefix;
- if (bss->anqp_3gpp == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return -1;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -662,7 +771,7 @@
#ifdef PCSC_FUNCS
compare:
#endif /* PCSC_FUNCS */
- if (plmn_id_match(bss->anqp_3gpp, imsi, mnc_len))
+ if (plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len))
break;
}
if (cred == NULL)
@@ -688,14 +797,43 @@
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
- /* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
- if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
- wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
+ if (interworking_set_hs20_params(ssid) < 0)
+ goto fail;
+
+ eap_type = EAP_TYPE_SIM;
+ if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
+ eap_type = EAP_TYPE_AKA;
+ if (cred->eap_method && cred->eap_method[0].vendor == EAP_VENDOR_IETF) {
+ if (cred->eap_method[0].method == EAP_TYPE_SIM ||
+ cred->eap_method[0].method == EAP_TYPE_AKA ||
+ cred->eap_method[0].method == EAP_TYPE_AKA_PRIME)
+ eap_type = cred->eap_method[0].method;
+ }
+
+ switch (eap_type) {
+ case EAP_TYPE_SIM:
+ prefix = '1';
+ res = wpa_config_set(ssid, "eap", "SIM", 0);
+ break;
+ case EAP_TYPE_AKA:
+ prefix = '0';
+ res = wpa_config_set(ssid, "eap", "AKA", 0);
+ break;
+ case EAP_TYPE_AKA_PRIME:
+ prefix = '6';
+ res = wpa_config_set(ssid, "eap", "AKA'", 0);
+ break;
+ default:
+ res = -1;
+ break;
+ }
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "Selected EAP method (%d) not supported",
+ eap_type);
goto fail;
}
- if (cred->pcsc && wpa_s->scard && scard_supports_umts(wpa_s->scard))
- wpa_config_set(ssid, "eap", "AKA", 0);
- if (!cred->pcsc && set_root_nai(ssid, cred->imsi, '1') < 0) {
+
+ if (!cred->pcsc && set_root_nai(ssid, cred->imsi, prefix) < 0) {
wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
goto fail;
}
@@ -730,6 +868,259 @@
}
+static int roaming_consortium_element_match(const u8 *ie, const u8 *rc_id,
+ size_t rc_len)
+{
+ const u8 *pos, *end;
+ u8 lens;
+
+ if (ie == NULL)
+ return 0;
+
+ pos = ie + 2;
+ end = ie + 2 + ie[1];
+
+ /* Roaming Consortium element:
+ * Number of ANQP OIs
+ * OI #1 and #2 lengths
+ * OI #1, [OI #2], [OI #3]
+ */
+
+ if (pos + 2 > end)
+ return 0;
+
+ pos++; /* skip Number of ANQP OIs */
+ lens = *pos++;
+ if (pos + (lens & 0x0f) + (lens >> 4) > end)
+ return 0;
+
+ if ((lens & 0x0f) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += lens & 0x0f;
+
+ if ((lens >> 4) == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += lens >> 4;
+
+ if (pos < end && (size_t) (end - pos) == rc_len &&
+ os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+
+ return 0;
+}
+
+
+static int roaming_consortium_anqp_match(const struct wpabuf *anqp,
+ const u8 *rc_id, size_t rc_len)
+{
+ const u8 *pos, *end;
+ u8 len;
+
+ if (anqp == NULL)
+ return 0;
+
+ pos = wpabuf_head(anqp);
+ end = pos + wpabuf_len(anqp);
+
+ /* Set of <OI Length, OI> duples */
+ while (pos < end) {
+ len = *pos++;
+ if (pos + len > end)
+ break;
+ if (len == rc_len && os_memcmp(pos, rc_id, rc_len) == 0)
+ return 1;
+ pos += len;
+ }
+
+ return 0;
+}
+
+
+static int roaming_consortium_match(const u8 *ie, const struct wpabuf *anqp,
+ const u8 *rc_id, size_t rc_len)
+{
+ return roaming_consortium_element_match(ie, rc_id, rc_len) ||
+ roaming_consortium_anqp_match(anqp, rc_id, rc_len);
+}
+
+
+static struct wpa_cred * interworking_credentials_available_roaming_consortium(
+ struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_cred *cred, *selected = NULL;
+ const u8 *ie;
+
+ ie = wpa_bss_get_ie(bss, WLAN_EID_ROAMING_CONSORTIUM);
+
+ if (ie == NULL &&
+ (bss->anqp == NULL || bss->anqp->roaming_consortium == NULL))
+ return NULL;
+
+ if (wpa_s->conf->cred == NULL)
+ return NULL;
+
+ for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+ if (cred->roaming_consortium_len == 0)
+ continue;
+
+ if (!roaming_consortium_match(ie,
+ bss->anqp ?
+ bss->anqp->roaming_consortium :
+ NULL,
+ cred->roaming_consortium,
+ cred->roaming_consortium_len))
+ continue;
+
+ if (selected == NULL ||
+ selected->priority < cred->priority)
+ selected = cred;
+ }
+
+ return selected;
+}
+
+
+static int interworking_set_eap_params(struct wpa_ssid *ssid,
+ struct wpa_cred *cred, int ttls)
+{
+ if (cred->eap_method) {
+ ttls = cred->eap_method->vendor == EAP_VENDOR_IETF &&
+ cred->eap_method->method == EAP_TYPE_TTLS;
+
+ os_free(ssid->eap.eap_methods);
+ ssid->eap.eap_methods =
+ os_malloc(sizeof(struct eap_method_type) * 2);
+ if (ssid->eap.eap_methods == NULL)
+ return -1;
+ os_memcpy(ssid->eap.eap_methods, cred->eap_method,
+ sizeof(*cred->eap_method));
+ ssid->eap.eap_methods[1].vendor = EAP_VENDOR_IETF;
+ ssid->eap.eap_methods[1].method = EAP_TYPE_NONE;
+ }
+
+ if (ttls && cred->username && cred->username[0]) {
+ const char *pos;
+ char *anon;
+ /* Use anonymous NAI in Phase 1 */
+ pos = os_strchr(cred->username, '@');
+ if (pos) {
+ size_t buflen = 9 + os_strlen(pos) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous%s", pos);
+ } else if (cred->realm) {
+ size_t buflen = 10 + os_strlen(cred->realm) + 1;
+ anon = os_malloc(buflen);
+ if (anon == NULL)
+ return -1;
+ os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
+ } else {
+ anon = os_strdup("anonymous");
+ if (anon == NULL)
+ return -1;
+ }
+ if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
+ 0) {
+ os_free(anon);
+ return -1;
+ }
+ os_free(anon);
+ }
+
+ if (cred->username && cred->username[0] &&
+ wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
+ return -1;
+
+ if (cred->password && cred->password[0]) {
+ if (cred->ext_password &&
+ wpa_config_set(ssid, "password", cred->password, 0) < 0)
+ return -1;
+ if (!cred->ext_password &&
+ wpa_config_set_quoted(ssid, "password", cred->password) <
+ 0)
+ return -1;
+ }
+
+ if (cred->client_cert && cred->client_cert[0] &&
+ wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
+ return -1;
+
+ if (cred->private_key && cred->private_key[0] &&
+ wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
+ return -1;
+
+ if (cred->private_key_passwd && cred->private_key_passwd[0] &&
+ wpa_config_set_quoted(ssid, "private_key_passwd",
+ cred->private_key_passwd) < 0)
+ return -1;
+
+ if (cred->phase1) {
+ os_free(ssid->eap.phase1);
+ ssid->eap.phase1 = os_strdup(cred->phase1);
+ }
+ if (cred->phase2) {
+ os_free(ssid->eap.phase2);
+ ssid->eap.phase2 = os_strdup(cred->phase2);
+ }
+
+ if (cred->ca_cert && cred->ca_cert[0] &&
+ wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int interworking_connect_roaming_consortium(
+ struct wpa_supplicant *wpa_s, struct wpa_cred *cred,
+ struct wpa_bss *bss, const u8 *ssid_ie)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " based on "
+ "roaming consortium match", MAC2STR(bss->bssid));
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL)
+ return -1;
+ wpas_notify_network_added(wpa_s, ssid);
+ wpa_config_set_network_defaults(ssid);
+ ssid->priority = cred->priority;
+ ssid->temporary = 1;
+ ssid->ssid = os_zalloc(ssid_ie[1] + 1);
+ if (ssid->ssid == NULL)
+ goto fail;
+ os_memcpy(ssid->ssid, ssid_ie + 2, ssid_ie[1]);
+ ssid->ssid_len = ssid_ie[1];
+
+ if (interworking_set_hs20_params(ssid) < 0)
+ goto fail;
+
+ if (cred->eap_method == NULL) {
+ wpa_printf(MSG_DEBUG, "Interworking: No EAP method set for "
+ "credential using roaming consortium");
+ goto fail;
+ }
+
+ if (interworking_set_eap_params(
+ ssid, cred,
+ cred->eap_method->vendor == EAP_VENDOR_IETF &&
+ cred->eap_method->method == EAP_TYPE_TTLS) < 0)
+ goto fail;
+
+ wpa_config_update_prio_list(wpa_s->conf);
+ interworking_reconnect(wpa_s);
+
+ return 0;
+
+fail:
+ wpas_notify_network_removed(wpa_s, ssid);
+ wpa_config_remove_network(wpa_s->conf, ssid->id);
+ return -1;
+}
+
+
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
{
struct wpa_cred *cred;
@@ -749,7 +1140,24 @@
return -1;
}
- realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+ /*
+ * We currently support only HS 2.0 networks and those are
+ * required to use WPA2-Enterprise.
+ */
+ wpa_printf(MSG_DEBUG, "Interworking: Network does not use "
+ "RSN");
+ return -1;
+ }
+
+ cred = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred)
+ return interworking_connect_roaming_consortium(wpa_s, cred,
+ bss, ie);
+
+ realm = nai_realm_parse(bss->anqp ? bss->anqp->nai_realm : NULL,
+ &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
@@ -800,62 +1208,13 @@
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
+ if (interworking_set_hs20_params(ssid) < 0)
+ goto fail;
+
if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
eap->method), 0) < 0)
goto fail;
- if (eap->method == EAP_TYPE_TTLS &&
- cred->username && cred->username[0]) {
- const char *pos;
- char *anon;
- /* Use anonymous NAI in Phase 1 */
- pos = os_strchr(cred->username, '@');
- if (pos) {
- size_t buflen = 9 + os_strlen(pos) + 1;
- anon = os_malloc(buflen);
- if (anon == NULL)
- goto fail;
- os_snprintf(anon, buflen, "anonymous%s", pos);
- } else if (cred->realm) {
- size_t buflen = 10 + os_strlen(cred->realm) + 1;
- anon = os_malloc(buflen);
- if (anon == NULL)
- goto fail;
- os_snprintf(anon, buflen, "anonymous@%s", cred->realm);
- } else {
- anon = os_strdup("anonymous");
- if (anon == NULL)
- goto fail;
- }
- if (wpa_config_set_quoted(ssid, "anonymous_identity", anon) <
- 0) {
- os_free(anon);
- goto fail;
- }
- os_free(anon);
- }
-
- if (cred->username && cred->username[0] &&
- wpa_config_set_quoted(ssid, "identity", cred->username) < 0)
- goto fail;
-
- if (cred->password && cred->password[0] &&
- wpa_config_set_quoted(ssid, "password", cred->password) < 0)
- goto fail;
-
- if (cred->client_cert && cred->client_cert[0] &&
- wpa_config_set_quoted(ssid, "client_cert", cred->client_cert) < 0)
- goto fail;
-
- if (cred->private_key && cred->private_key[0] &&
- wpa_config_set_quoted(ssid, "private_key", cred->private_key) < 0)
- goto fail;
-
- if (cred->private_key_passwd && cred->private_key_passwd[0] &&
- wpa_config_set_quoted(ssid, "private_key_passwd",
- cred->private_key_passwd) < 0)
- goto fail;
-
switch (eap->method) {
case EAP_TYPE_TTLS:
if (eap->inner_method) {
@@ -899,8 +1258,8 @@
break;
}
- if (cred->ca_cert && cred->ca_cert[0] &&
- wpa_config_set_quoted(ssid, "ca_cert", cred->ca_cert) < 0)
+ if (interworking_set_eap_params(ssid, cred,
+ eap->method == EAP_TYPE_TTLS) < 0)
goto fail;
nai_realm_free(realm, count);
@@ -925,7 +1284,7 @@
int ret;
#ifdef INTERWORKING_3GPP
- if (bss->anqp_3gpp == NULL)
+ if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL)
return NULL;
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
@@ -958,7 +1317,7 @@
#endif /* PCSC_FUNCS */
wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from "
MACSTR, MAC2STR(bss->bssid));
- ret = plmn_id_match(bss->anqp_3gpp, imsi, mnc_len);
+ ret = plmn_id_match(bss->anqp->anqp_3gpp, imsi, mnc_len);
wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
if (ret) {
if (selected == NULL ||
@@ -978,7 +1337,7 @@
struct nai_realm *realm;
u16 count, i;
- if (bss->anqp_nai_realm == NULL)
+ if (bss->anqp == NULL || bss->anqp->nai_realm == NULL)
return NULL;
if (wpa_s->conf->cred == NULL)
@@ -986,7 +1345,7 @@
wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
MACSTR, MAC2STR(bss->bssid));
- realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+ realm = nai_realm_parse(bss->anqp->nai_realm, &count);
if (realm == NULL) {
wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
"Realm list from " MACSTR, MAC2STR(bss->bssid));
@@ -1027,6 +1386,13 @@
if (!cred)
cred = cred2;
+ cred2 = interworking_credentials_available_roaming_consortium(wpa_s,
+ bss);
+ if (cred && cred2 && cred2->priority >= cred->priority)
+ cred = cred2;
+ if (!cred)
+ cred = cred2;
+
return cred;
}
@@ -1071,8 +1437,19 @@
for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
#ifdef INTERWORKING_3GPP
- if (cred->imsi &&
- build_root_nai(nai, sizeof(nai), cred->imsi, 0) == 0) {
+ char *imsi = NULL;
+ int mnc_len = 0;
+ if (cred->imsi)
+ imsi = cred->imsi;
+#ifdef CONFIG_PCSC
+ else if (cred->pcsc && wpa_s->conf->pcsc_reader &&
+ wpa_s->scard && wpa_s->imsi[0]) {
+ imsi = wpa_s->imsi;
+ mnc_len = wpa_s->mnc_len;
+ }
+#endif /* CONFIG_PCSC */
+ if (imsi && build_root_nai(nai, sizeof(nai), imsi, mnc_len, 0)
+ == 0) {
realm = os_strchr(nai, '@');
if (realm)
realm++;
@@ -1138,8 +1515,19 @@
cred = interworking_credentials_available(wpa_s, bss);
if (!cred)
continue;
+ if (!wpa_bss_get_ie(bss, WLAN_EID_RSN)) {
+ /*
+ * We currently support only HS 2.0 networks and those
+ * are required to use WPA2-Enterprise.
+ */
+ wpa_printf(MSG_DEBUG, "Interworking: Credential match "
+ "with " MACSTR " but network does not use "
+ "RSN", MAC2STR(bss->bssid));
+ continue;
+ }
count++;
- res = interworking_home_sp(wpa_s, bss->anqp_domain_name);
+ res = interworking_home_sp(wpa_s, bss->anqp ?
+ bss->anqp->domain_name : NULL);
if (res > 0)
type = "home";
else if (res == 0)
@@ -1148,7 +1536,9 @@
type = "unknown";
wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR " type=%s",
MAC2STR(bss->bssid), type);
- if (wpa_s->auto_select) {
+ if (wpa_s->auto_select ||
+ (wpa_s->conf->auto_interworking &&
+ wpa_s->auto_network_select)) {
if (selected == NULL ||
cred->priority > selected_prio) {
selected = bss;
@@ -1178,7 +1568,16 @@
if (interworking_find_network_match(wpa_s)) {
wpa_printf(MSG_DEBUG, "Interworking: Possible BSS "
"match for enabled network configurations");
- interworking_reconnect(wpa_s);
+ if (wpa_s->auto_select)
+ interworking_reconnect(wpa_s);
+ return;
+ }
+
+ if (wpa_s->auto_network_select) {
+ wpa_printf(MSG_DEBUG, "Interworking: Continue "
+ "scanning after ANQP fetch");
+ wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval,
+ 0);
return;
}
@@ -1191,6 +1590,38 @@
}
+static struct wpa_bss_anqp *
+interworking_match_anqp_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+ struct wpa_bss *other;
+
+ if (is_zero_ether_addr(bss->hessid))
+ return NULL; /* Cannot be in the same homegenous ESS */
+
+ dl_list_for_each(other, &wpa_s->bss, struct wpa_bss, list) {
+ if (other == bss)
+ continue;
+ if (other->anqp == NULL)
+ continue;
+ if (!(other->flags & WPA_BSS_ANQP_FETCH_TRIED))
+ continue;
+ if (os_memcmp(bss->hessid, other->hessid, ETH_ALEN) != 0)
+ continue;
+ if (bss->ssid_len != other->ssid_len ||
+ os_memcmp(bss->ssid, other->ssid, bss->ssid_len) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "Interworking: Share ANQP data with "
+ "already fetched BSSID " MACSTR " and " MACSTR,
+ MAC2STR(other->bssid), MAC2STR(bss->bssid));
+ other->anqp->users++;
+ return other->anqp;
+ }
+
+ return NULL;
+}
+
+
static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@@ -1208,6 +1639,17 @@
continue; /* AP does not support Interworking */
if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+ if (bss->anqp == NULL) {
+ bss->anqp = interworking_match_anqp_info(wpa_s,
+ bss);
+ if (bss->anqp) {
+ /* Shared data already fetched */
+ continue;
+ }
+ bss->anqp = wpa_bss_anqp_alloc();
+ if (bss->anqp == NULL)
+ break;
+ }
found++;
bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
@@ -1226,7 +1668,7 @@
}
-static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
{
struct wpa_bss *bss;
@@ -1244,6 +1686,7 @@
return 0;
wpa_s->network_select = 0;
+ wpa_s->fetch_all_anqp = 1;
interworking_start_fetch_anqp(wpa_s);
@@ -1302,10 +1745,14 @@
{
const u8 *pos = data;
struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+ struct wpa_bss_anqp *anqp = NULL;
#ifdef CONFIG_HS20
u8 type;
#endif /* CONFIG_HS20 */
+ if (bss)
+ anqp = bss->anqp;
+
switch (info_id) {
case ANQP_CAPABILITY_LIST:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
@@ -1315,9 +1762,9 @@
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Venue Name", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_venue_name);
- bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->venue_name);
+ anqp->venue_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_NETWORK_AUTH_TYPE:
@@ -1326,10 +1773,9 @@
MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
"Type", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_network_auth_type);
- bss->anqp_network_auth_type =
- wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->network_auth_type);
+ anqp->network_auth_type = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_ROAMING_CONSORTIUM:
@@ -1337,10 +1783,9 @@
" Roaming Consortium list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_roaming_consortium);
- bss->anqp_roaming_consortium =
- wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->roaming_consortium);
+ anqp->roaming_consortium = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_IP_ADDR_TYPE_AVAILABILITY:
@@ -1349,9 +1794,9 @@
MAC2STR(sa));
wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_ip_addr_type_availability);
- bss->anqp_ip_addr_type_availability =
+ if (anqp) {
+ wpabuf_free(anqp->ip_addr_type_availability);
+ anqp->ip_addr_type_availability =
wpabuf_alloc_copy(pos, slen);
}
break;
@@ -1359,9 +1804,9 @@
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" NAI Realm list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_nai_realm);
- bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->nai_realm);
+ anqp->nai_realm = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_3GPP_CELLULAR_NETWORK:
@@ -1369,18 +1814,18 @@
" 3GPP Cellular Network information", MAC2STR(sa));
wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_3gpp);
- bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->anqp_3gpp);
+ anqp->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_DOMAIN_NAME:
wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
" Domain Name list", MAC2STR(sa));
wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
- if (bss) {
- wpabuf_free(bss->anqp_domain_name);
- bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
+ if (anqp) {
+ wpabuf_free(anqp->domain_name);
+ anqp->domain_name = wpabuf_alloc_copy(pos, slen);
}
break;
case ANQP_VENDOR_SPECIFIC:
@@ -1484,7 +1929,9 @@
{
interworking_stop_fetch_anqp(wpa_s);
wpa_s->network_select = 1;
+ wpa_s->auto_network_select = 0;
wpa_s->auto_select = !!auto_select;
+ wpa_s->fetch_all_anqp = 0;
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
@@ -1493,3 +1940,84 @@
return 0;
}
+
+
+static void gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
+ enum gas_query_result result,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *resp, u16 status_code)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_msg(wpa_s, MSG_INFO, GAS_RESPONSE_INFO "addr=" MACSTR
+ " dialog_token=%d status_code=%d resp_len=%d",
+ MAC2STR(addr), dialog_token, status_code,
+ resp ? (int) wpabuf_len(resp) : -1);
+ if (!resp)
+ return;
+
+ wpabuf_free(wpa_s->last_gas_resp);
+ wpa_s->last_gas_resp = wpabuf_dup(resp);
+ if (wpa_s->last_gas_resp == NULL)
+ return;
+ os_memcpy(wpa_s->last_gas_addr, addr, ETH_ALEN);
+ wpa_s->last_gas_dialog_token = dialog_token;
+}
+
+
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *query)
+{
+ struct wpabuf *buf;
+ int ret = 0;
+ int freq;
+ struct wpa_bss *bss;
+ int res;
+ size_t len;
+ u8 query_resp_len_limit = 0, pame_bi = 0;
+
+ freq = wpa_s->assoc_freq;
+ bss = wpa_bss_get_bssid(wpa_s, dst);
+ if (bss)
+ freq = bss->freq;
+ if (freq <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "GAS request to " MACSTR " (freq %d MHz)",
+ MAC2STR(dst), freq);
+ wpa_hexdump_buf(MSG_DEBUG, "Advertisement Protocol ID", adv_proto);
+ wpa_hexdump_buf(MSG_DEBUG, "GAS Query", query);
+
+ len = 3 + wpabuf_len(adv_proto) + 2;
+ if (query)
+ len += wpabuf_len(query);
+ buf = gas_build_initial_req(0, len);
+ if (buf == NULL)
+ return -1;
+
+ /* Advertisement Protocol IE */
+ wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+ wpabuf_put_u8(buf, 1 + wpabuf_len(adv_proto)); /* Length */
+ wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+ (pame_bi ? 0x80 : 0));
+ wpabuf_put_buf(buf, adv_proto);
+
+ /* GAS Query */
+ if (query) {
+ wpabuf_put_le16(buf, wpabuf_len(query));
+ wpabuf_put_buf(buf, query);
+ } else
+ wpabuf_put_le16(buf, 0);
+
+ res = gas_query_req(wpa_s->gas, dst, freq, buf, gas_resp_cb, wpa_s);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "GAS: Failed to send Query Request");
+ ret = -1;
+ } else
+ wpa_printf(MSG_DEBUG, "GAS: Query started with dialog token "
+ "%u", res);
+
+ wpabuf_free(buf);
+ return ret;
+}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
index 7dda8d8..cb8438e 100644
--- a/wpa_supplicant/interworking.h
+++ b/wpa_supplicant/interworking.h
@@ -1,6 +1,6 @@
/*
* Interworking (IEEE 802.11u)
- * Copyright (c) 2011, Qualcomm Atheros
+ * Copyright (c) 2011-2012, Qualcomm Atheros
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -17,9 +17,13 @@
enum gas_query_result result,
const struct wpabuf *adv_proto,
const struct wpabuf *resp, u16 status_code);
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *adv_proto,
+ const struct wpabuf *query);
int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
#endif /* INTERWORKING_H */
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index 80aac77..19f7ce6 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -101,20 +101,31 @@
}
-static void wpa_supplicant_fd_workaround(void)
+static void wpa_supplicant_fd_workaround(int start)
{
#ifdef __linux__
- int s, i;
+ static int fd[3] = { -1, -1, -1 };
+ int i;
/* When started from pcmcia-cs scripts, wpa_supplicant might start with
* fd 0, 1, and 2 closed. This will cause some issues because many
* places in wpa_supplicant are still printing out to stdout. As a
* workaround, make sure that fd's 0, 1, and 2 are not used for other
* sockets. */
- for (i = 0; i < 3; i++) {
- s = open("/dev/null", O_RDWR);
- if (s > 2) {
- close(s);
- break;
+ if (start) {
+ for (i = 0; i < 3; i++) {
+ fd[i] = open("/dev/null", O_RDWR);
+ if (fd[i] > 2) {
+ close(fd[i]);
+ fd[i] = -1;
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 3; i++) {
+ if (fd[i] >= 0) {
+ close(fd[i]);
+ fd[i] = -1;
+ }
}
}
#endif /* __linux__ */
@@ -140,7 +151,7 @@
return -1;
iface_count = 1;
- wpa_supplicant_fd_workaround();
+ wpa_supplicant_fd_workaround(1);
for (;;) {
c = getopt(argc, argv,
@@ -241,8 +252,8 @@
break;
case 'N':
iface_count++;
- iface = os_realloc(ifaces, iface_count *
- sizeof(struct wpa_interface));
+ iface = os_realloc_array(ifaces, iface_count,
+ sizeof(struct wpa_interface));
if (iface == NULL)
goto out;
ifaces = iface;
@@ -288,6 +299,7 @@
wpa_supplicant_deinit(global);
out:
+ wpa_supplicant_fd_workaround(0);
os_free(ifaces);
os_free(params.pid_file);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index f4df4b0..73d082e 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -61,6 +61,27 @@
#define P2P_MAX_INITIAL_CONN_WAIT 10
#endif /* P2P_MAX_INITIAL_CONN_WAIT */
+#ifndef P2P_CONCURRENT_SEARCH_DELAY
+#ifdef ANDROID_P2P
+#define P2P_CONCURRENT_SEARCH_DELAY 0
+#else
+#define P2P_CONCURRENT_SEARCH_DELAY 500
+#endif
+#endif /* P2P_CONCURRENT_SEARCH_DELAY */
+
+enum p2p_group_removal_reason {
+ P2P_GROUP_REMOVAL_UNKNOWN,
+ P2P_GROUP_REMOVAL_SILENT,
+ P2P_GROUP_REMOVAL_FORMATION_FAILED,
+ P2P_GROUP_REMOVAL_REQUESTED,
+ P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
+ P2P_GROUP_REMOVAL_UNAVAILABLE,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
+#ifdef ANDROID_P2P
+ P2P_GROUP_REMOVAL_FREQ_CONFLICT
+#endif
+};
+
#ifdef ANDROID_P2P
static int wpas_global_scan_in_progress(struct wpa_supplicant *wpa_s);
#endif
@@ -129,6 +150,7 @@
const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
{
struct wpa_supplicant *wpa_s = ctx;
+ struct wpa_supplicant *ifs;
struct wpa_driver_scan_params params;
int ret;
struct wpabuf *wps_ie, *ies;
@@ -138,6 +160,31 @@
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs->sta_scan_pending &&
+ wpas_p2p_in_progress(wpa_s) == 2) {
+ wpa_printf(MSG_DEBUG, "Delaying P2P scan to allow "
+ "pending station mode scan to be "
+ "completed on interface %s", ifs->ifname);
+#ifdef ANDROID_P2P
+ ifs->p2p_cb_on_scan_complete = 1;
+#else
+ wpa_s->p2p_cb_on_scan_complete = 1;
+#endif
+ wpa_supplicant_req_scan(ifs, 0, 0);
+ return 1;
+ }
+#ifdef ANDROID_P2P
+ else if(ifs->scanning) {
+ wpa_printf(MSG_DEBUG, "Wait for the STA scan"
+ "to be "
+ "completed on interface %s", ifs->ifname);
+ ifs->p2p_cb_on_scan_complete = 1;
+ return 1;
+ }
+#endif
+ }
+
os_memset(¶ms, 0, sizeof(params));
/* P2P Wildcard SSID */
@@ -241,7 +288,8 @@
}
-static void wpas_p2p_group_delete(struct wpa_supplicant *wpa_s, int silent)
+static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
+ enum p2p_group_removal_reason removal_reason)
{
struct wpa_ssid *ssid;
char *gtype;
@@ -261,6 +309,13 @@
break;
ssid = ssid->next;
}
+ if (ssid == NULL &&
+ wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE)
+ {
+ wpa_printf(MSG_ERROR, "P2P: P2P group interface "
+ "not found");
+ return -1;
+ }
}
if (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_GO)
gtype = "GO";
@@ -279,10 +334,13 @@
P2P_EVENT_CROSS_CONNECT_DISABLE "%s %s",
wpa_s->ifname, wpa_s->cross_connect_uplink);
}
- switch (wpa_s->removal_reason) {
+ switch (removal_reason) {
case P2P_GROUP_REMOVAL_REQUESTED:
reason = " reason=REQUESTED";
break;
+ case P2P_GROUP_REMOVAL_FORMATION_FAILED:
+ reason = " reason=FORMATION_FAILED";
+ break;
case P2P_GROUP_REMOVAL_IDLE_TIMEOUT:
reason = " reason=IDLE";
break;
@@ -301,7 +359,7 @@
reason = "";
break;
}
- if (!silent) {
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT) {
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_REMOVED "%s %s%s",
wpa_s->ifname, gtype, reason);
@@ -310,7 +368,7 @@
if (eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL) > 0)
wpa_printf(MSG_DEBUG, "P2P: Cancelled P2P group idle timeout");
- if (!silent && ssid)
+ if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
if (wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
@@ -327,7 +385,7 @@
if (wpa_s && ifname)
wpa_drv_if_remove(wpa_s, type, ifname);
os_free(ifname);
- return;
+ return 1;
}
wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
@@ -360,6 +418,8 @@
wpa_supplicant_ap_deinit(wpa_s);
else
wpa_drv_deinit_p2p_cli(wpa_s);
+
+ return 0;
}
@@ -517,6 +577,7 @@
struct wpa_ssid *ssid, *s;
u8 *n;
size_t i;
+ int found = 0;
ssid = wpa_s->current_ssid;
if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
@@ -537,17 +598,40 @@
for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
- ETH_ALEN) == 0)
- return; /* already in list */
+ ETH_ALEN) != 0)
+ continue;
+
+ if (i == s->num_p2p_clients - 1)
+ return; /* already the most recent entry */
+
+ /* move the entry to mark it most recent */
+ os_memmove(s->p2p_client_list + i * ETH_ALEN,
+ s->p2p_client_list + (i + 1) * ETH_ALEN,
+ (s->num_p2p_clients - i - 1) * ETH_ALEN);
+ os_memcpy(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * ETH_ALEN, addr, ETH_ALEN);
+ found = 1;
+ break;
}
- n = os_realloc(s->p2p_client_list,
- (s->num_p2p_clients + 1) * ETH_ALEN);
- if (n == NULL)
- return;
- os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
- s->p2p_client_list = n;
- s->num_p2p_clients++;
+ if (!found && s->num_p2p_clients < P2P_MAX_STORED_CLIENTS) {
+ n = os_realloc_array(s->p2p_client_list,
+ s->num_p2p_clients + 1, ETH_ALEN);
+ if (n == NULL)
+ return;
+ os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+ s->p2p_client_list = n;
+ s->num_p2p_clients++;
+ } else if (!found) {
+ /* Not enough room for an additional entry - drop the oldest
+ * entry */
+ os_memmove(s->p2p_client_list,
+ s->p2p_client_list + ETH_ALEN,
+ (s->num_p2p_clients - 1) * ETH_ALEN);
+ os_memcpy(s->p2p_client_list +
+ (s->num_p2p_clients - 1) * ETH_ALEN,
+ addr, ETH_ALEN);
+ }
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->parent->conf->update_config &&
@@ -580,7 +664,8 @@
if (!success) {
wpa_msg(wpa_s->parent, MSG_INFO,
P2P_EVENT_GROUP_FORMATION_FAILURE);
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_FORMATION_FAILED);
return;
}
@@ -621,6 +706,13 @@
* packets.
*/
wpa_s->show_group_started = 1;
+#ifdef ANDROID_P2P
+ /* For client Second phase of Group formation (4-way handshake) can be still pending
+ * So we need to restore wpa_s->global->p2p_group_formation */
+ wpa_printf(MSG_INFO, "Restoring back wpa_s->global->p2p_group_formation to wpa_s %p\n", wpa_s);
+ wpa_s->global->p2p_group_formation = wpa_s;
+#endif
+
} else if (ssid && ssid->passphrase == NULL && ssid->psk_set) {
char psk[65];
wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
@@ -829,6 +921,7 @@
ssid->mode = group_formation ? WPAS_MODE_P2P_GROUP_FORMATION :
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
+ ssid->ht40 = params->ht40;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -839,6 +932,7 @@
ssid->proto = WPA_PROTO_RSN;
ssid->pairwise_cipher = WPA_CIPHER_CCMP;
ssid->passphrase = os_strdup(params->passphrase);
+ ssid->ap_max_inactivity = wpa_s->parent->conf->p2p_go_max_inactivity;
wpa_s->ap_configured_cb = p2p_go_configured;
wpa_s->ap_configured_cb_ctx = wpa_s;
@@ -1026,6 +1120,9 @@
return;
}
+ if (wpa_s->p2p_go_ht40)
+ res->ht40 = 1;
+
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
wpas_notify_p2p_go_neg_completed(wpa_s, res);
@@ -1100,16 +1197,27 @@
#ifndef CONFIG_NO_STDOUT_DEBUG
struct wpa_supplicant *wpa_s = ctx;
char devtype[WPS_DEV_TYPE_BUFSIZE];
+#define WFD_DEV_INFO_SIZE 9
+ char wfd_dev_info_hex[2 * WFD_DEV_INFO_SIZE + 1];
+
+#ifdef CONFIG_WIFI_DISPLAY
+ if (info->wfd_subelems) {
+ wpa_snprintf_hex(wfd_dev_info_hex, sizeof(wfd_dev_info_hex),
+ wpabuf_head(info->wfd_subelems),
+ WFD_DEV_INFO_SIZE);
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_FOUND MACSTR
" p2p_dev_addr=" MACSTR
" pri_dev_type=%s name='%s' config_methods=0x%x "
- "dev_capab=0x%x group_capab=0x%x",
+ "dev_capab=0x%x group_capab=0x%x%s%s",
MAC2STR(addr), MAC2STR(info->p2p_device_addr),
wps_dev_type_bin2str(info->pri_dev_type, devtype,
sizeof(devtype)),
info->device_name, info->config_methods,
- info->dev_capab, info->group_capab);
+ info->dev_capab, info->group_capab,
+ wfd_dev_info_hex[0] ? " wfd_dev_info=0x" : "", wfd_dev_info_hex);
#endif /* CONFIG_NO_STDOUT_DEBUG */
wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
@@ -1443,6 +1551,62 @@
}
+#ifdef CONFIG_WIFI_DISPLAY
+static void wpas_sd_req_wfd(struct wpa_supplicant *wpa_s,
+ struct wpabuf *resp, u8 srv_trans_id,
+ const u8 *query, size_t query_len)
+{
+ const u8 *pos;
+ u8 role;
+ u8 *len_pos;
+
+ wpa_hexdump(MSG_DEBUG, "P2P: SD Request for WFD", query, query_len);
+
+ if (!wpa_s->global->wifi_display) {
+ wpa_printf(MSG_DEBUG, "P2P: WFD protocol not available");
+ wpas_sd_add_proto_not_avail(resp, P2P_SERV_WIFI_DISPLAY,
+ srv_trans_id);
+ return;
+ }
+
+ if (query_len < 1) {
+ wpa_printf(MSG_DEBUG, "P2P: Missing WFD Requested Device "
+ "Role");
+ return;
+ }
+
+ if (wpabuf_tailroom(resp) < 5)
+ return;
+
+ pos = query;
+ role = *pos++;
+ wpa_printf(MSG_DEBUG, "P2P: WSD for device role 0x%x", role);
+
+ /* TODO: role specific handling */
+
+ /* Length (to be filled) */
+ len_pos = wpabuf_put(resp, 2);
+ wpabuf_put_u8(resp, P2P_SERV_WIFI_DISPLAY);
+ wpabuf_put_u8(resp, srv_trans_id);
+ wpabuf_put_u8(resp, P2P_SD_SUCCESS); /* Status Code */
+
+ while (pos < query + query_len) {
+ if (*pos < MAX_WFD_SUBELEMS &&
+ wpa_s->global->wfd_subelem[*pos] &&
+ wpabuf_tailroom(resp) >=
+ wpabuf_len(wpa_s->global->wfd_subelem[*pos])) {
+ wpa_printf(MSG_DEBUG, "P2P: Add WSD response "
+ "subelement %u", *pos);
+ wpabuf_put_buf(resp, wpa_s->global->wfd_subelem[*pos]);
+ }
+ pos++;
+ }
+
+ WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(resp, 0) - len_pos - 2);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
u16 update_indic, const u8 *tlvs, size_t tlvs_len)
{
@@ -1534,6 +1698,12 @@
wpas_sd_req_upnp(wpa_s, resp, srv_trans_id,
pos, tlv_end - pos);
break;
+#ifdef CONFIG_WIFI_DISPLAY
+ case P2P_SERV_WIFI_DISPLAY:
+ wpas_sd_req_wfd(wpa_s, resp, srv_trans_id,
+ pos, tlv_end - pos);
+ break;
+#endif /* CONFIG_WIFI_DISPLAY */
default:
wpa_printf(MSG_DEBUG, "P2P: Unavailable service "
"protocol %u", srv_proto);
@@ -1651,6 +1821,88 @@
}
+#ifdef CONFIG_WIFI_DISPLAY
+
+static u64 wpas_p2p_sd_request_wfd(struct wpa_supplicant *wpa_s, const u8 *dst,
+ const struct wpabuf *tlvs)
+{
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
+ return 0;
+ if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+ return 0;
+ return (uintptr_t) p2p_sd_request_wfd(wpa_s->global->p2p, dst, tlvs);
+}
+
+
+#define MAX_WFD_SD_SUBELEMS 20
+
+static void wfd_add_sd_req_role(struct wpabuf *tlvs, u8 id, u8 role,
+ const char *subelems)
+{
+ u8 *len;
+ const char *pos;
+ int val;
+ int count = 0;
+
+ len = wpabuf_put(tlvs, 2);
+ wpabuf_put_u8(tlvs, P2P_SERV_WIFI_DISPLAY); /* Service Protocol Type */
+ wpabuf_put_u8(tlvs, id); /* Service Transaction ID */
+
+ wpabuf_put_u8(tlvs, role);
+
+ pos = subelems;
+ while (*pos) {
+ val = atoi(pos);
+ if (val >= 0 && val < 256) {
+ wpabuf_put_u8(tlvs, val);
+ count++;
+ if (count == MAX_WFD_SD_SUBELEMS)
+ break;
+ }
+ pos = os_strchr(pos + 1, ',');
+ if (pos == NULL)
+ break;
+ pos++;
+ }
+
+ WPA_PUT_LE16(len, (u8 *) wpabuf_put(tlvs, 0) - len - 2);
+}
+
+
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *role)
+{
+ struct wpabuf *tlvs;
+ u64 ret;
+ const char *subelems;
+ u8 id = 1;
+
+ subelems = os_strchr(role, ' ');
+ if (subelems == NULL)
+ return 0;
+ subelems++;
+
+ tlvs = wpabuf_alloc(4 * (2 + 1 + 1 + 1 + MAX_WFD_SD_SUBELEMS));
+ if (tlvs == NULL)
+ return 0;
+
+ if (os_strstr(role, "[source]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x00, subelems);
+ if (os_strstr(role, "[pri-sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x01, subelems);
+ if (os_strstr(role, "[sec-sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x02, subelems);
+ if (os_strstr(role, "[source+sink]"))
+ wfd_add_sd_req_role(tlvs, id++, 0x03, subelems);
+
+ ret = wpas_p2p_sd_request_wfd(wpa_s, dst, tlvs);
+ wpabuf_free(tlvs);
+ return ret;
+}
+
+#endif /* CONFIG_WIFI_DISPLAY */
+
+
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
{
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
@@ -2078,7 +2330,7 @@
MAC2STR(sa), op_freq);
if (s) {
wpas_p2p_group_add_persistent(
- wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0);
+ wpa_s, s, s->mode == WPAS_MODE_P2P_GO, 0, 0);
} else if (bssid) {
wpas_p2p_join(wpa_s, bssid, go_dev_addr,
wpa_s->p2p_wps_method, 0);
@@ -2145,7 +2397,9 @@
}
wpas_p2p_group_add_persistent(wpa_s, ssid,
- ssid->mode == WPAS_MODE_P2P_GO, 0);
+ ssid->mode == WPAS_MODE_P2P_GO,
+ wpa_s->p2p_persistent_go_freq,
+ wpa_s->p2p_go_ht40);
}
@@ -2282,26 +2536,48 @@
enum { BW20, BW40PLUS, BW40MINUS } bw;
};
+static struct p2p_oper_class_map op_class[] = {
+ { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
+ { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
+#if 0 /* Do not enable HT40 on 2 GHz for now */
+ { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
+ { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
+#endif
+ { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
+ { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
+ { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
+ { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
+ { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
+ { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+ { -1, 0, 0, 0, 0, BW20 }
+};
+
+
+static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ int flag;
+
+ if (!has_channel(wpa_s->global, mode, channel, &flag))
+ return -1;
+ if (bw == BW40MINUS &&
+ (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
+ !has_channel(wpa_s->global, mode, channel - 4, NULL)))
+ return 0;
+ if (bw == BW40PLUS &&
+ (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
+ !has_channel(wpa_s->global, mode, channel + 4, NULL)))
+ return 0;
+ return 1;
+}
+
+
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
struct p2p_channels *chan)
{
struct hostapd_hw_modes *mode;
int cla, op;
- struct p2p_oper_class_map op_class[] = {
- { HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
- { HOSTAPD_MODE_IEEE80211G, 82, 14, 14, 1, BW20 },
-#if 0 /* Do not enable HT40 on 2 GHz for now */
- { HOSTAPD_MODE_IEEE80211G, 83, 1, 9, 1, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211G, 84, 5, 13, 1, BW40MINUS },
-#endif
- { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20 },
- { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
- { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
- { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
- { -1, 0, 0, 0, 0, BW20 }
- };
if (wpa_s->hw.modes == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
@@ -2321,16 +2597,7 @@
if (mode == NULL)
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- int flag;
- if (!has_channel(wpa_s->global, mode, ch, &flag))
- continue;
- if (o->bw == BW40MINUS &&
- (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(wpa_s->global, mode, ch - 4, NULL)))
- continue;
- if (o->bw == BW40PLUS &&
- (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(wpa_s->global, mode, ch + 4, NULL)))
+ if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
continue;
if (reg == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Add operating "
@@ -2354,6 +2621,32 @@
}
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ int op, ret;
+
+ for (op = 0; op_class[op].op_class; op++) {
+ struct p2p_oper_class_map *o = &op_class[op];
+ u8 ch;
+
+ for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+ if (o->mode != HOSTAPD_MODE_IEEE80211A ||
+ o->bw == BW20 || ch != channel)
+ continue;
+ ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ if (ret < 0)
+ continue;
+ else if (ret > 0)
+ return (o->bw == BW40MINUS) ? -1 : 1;
+ else
+ return 0;
+ }
+ }
+ return 0;
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -2534,7 +2827,6 @@
p2p.p2p_intra_bss = wpa_s->conf->p2p_intra_bss;
-
#ifdef ANDROID_P2P
if(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)
p2p.p2p_concurrency = P2P_MULTI_CHANNEL_CONCURRENT;
@@ -2601,13 +2893,14 @@
{
struct wpa_supplicant *wpa_s, *tmp;
+ wpa_s = global->ifaces;
+ if (wpa_s)
+ wpas_p2p_service_flush(wpa_s);
+
if (global->p2p == NULL)
return;
/* Remove remaining P2P group interfaces */
- wpa_s = global->ifaces;
- if (wpa_s)
- wpas_p2p_service_flush(wpa_s);
while (wpa_s && wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE)
wpa_s = wpa_s->next;
while (wpa_s) {
@@ -2671,6 +2964,13 @@
force_freq, persistent_group);
}
+ /*
+ * Increase GO config timeout if HT40 is used since it takes some time
+ * to scan channels for coex purposes before the BSS can be started.
+ */
+ p2p_set_config_timeout(wpa_s->global->p2p,
+ wpa_s->p2p_go_ht40 ? 255 : 100, 20);
+
return p2p_connect(wpa_s->global->p2p, peer_addr, wps_method,
go_intent, own_interface_addr, force_freq,
persistent_group, ssid ? ssid->ssid : NULL,
@@ -2875,7 +3175,8 @@
wpa_s->p2p_go_intent,
wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
- wpa_s->p2p_pd_before_go_neg);
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40);
return;
}
@@ -3004,7 +3305,17 @@
struct wpabuf *wps_ie, *ies;
size_t ielen;
int freqs[2] = { 0, 0 };
+#ifdef ANDROID_P2P
+ int oper_freq;
+ /* If freq is not provided, check the operating freq of the GO and do a
+ * a directed scan to save time
+ */
+ if(!freq) {
+ freq = (oper_freq = p2p_get_oper_freq(wpa_s->global->p2p,
+ wpa_s->pending_join_iface_addr) == -1) ? 0 : oper_freq;
+ }
+#endif
os_memset(¶ms, 0, sizeof(params));
/* P2P Wildcard SSID */
@@ -3161,6 +3472,7 @@
* parameters or -1 to generate new values (SSID/passphrase)
* @pd: Whether to send Provision Discovery prior to GO Negotiation as an
* interoperability workaround when initiating group formation
+ * @ht40: Start GO with 40 MHz channel width
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -3168,7 +3480,8 @@
int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join, int auth,
- int go_intent, int freq, int persistent_id, int pd)
+ int go_intent, int freq, int persistent_id, int pd,
+ int ht40)
{
int force_freq = 0, oper_freq = 0;
u8 bssid[ETH_ALEN];
@@ -3200,6 +3513,7 @@
wpa_s->p2p_connect_freq = freq;
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->p2p_pd_before_go_neg = !!pd;
+ wpa_s->p2p_go_ht40 = !!ht40;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -3431,13 +3745,14 @@
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq)
+ int freq, int ht40)
{
u8 bssid[ETH_ALEN];
int res;
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
+ params->ht40 = ht40;
if (freq) {
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on forced "
"frequency %d MHz", freq);
@@ -3549,7 +3864,7 @@
* i.e., without using Group Owner Negotiation.
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq)
+ int freq, int ht40)
{
struct p2p_go_neg_results params;
unsigned int r;
@@ -3607,7 +3922,7 @@
return -1;
}
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq))
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40))
return -1;
if (params.freq &&
!p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
@@ -3674,7 +3989,7 @@
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq)
+ int freq, int ht40)
{
struct p2p_go_neg_results params;
int go = 0;
@@ -3700,7 +4015,7 @@
if (ssid->mode != WPAS_MODE_P2P_GO)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq))
+ if (wpas_p2p_init_go_params(wpa_s, ¶ms, freq, ht40))
return -1;
params.role_go = 1;
@@ -3939,7 +4254,7 @@
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id)
+ const u8 *dev_id, unsigned int search_delay)
{
wpas_p2p_clear_pending_action_tx(wpa_s);
wpa_s->p2p_long_listen = 0;
@@ -3954,7 +4269,8 @@
wpa_supplicant_cancel_sched_scan(wpa_s);
return p2p_find(wpa_s->global->p2p, timeout, type,
- num_req_dev_types, req_dev_types, dev_id);
+ num_req_dev_types, req_dev_types, dev_id,
+ search_delay);
}
@@ -4127,11 +4443,14 @@
/* Invite to reinvoke a persistent group */
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- struct wpa_ssid *ssid, const u8 *go_dev_addr)
+ struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+ int ht40)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
+ wpa_s->p2p_persistent_go_freq = freq;
+ wpa_s->p2p_go_ht40 = !!ht40;
if (ssid->mode == WPAS_MODE_P2P_GO) {
role = P2P_INVITE_ROLE_GO;
if (peer_addr == NULL) {
@@ -4165,7 +4484,7 @@
return -1;
return p2p_invite(wpa_s->global->p2p, peer_addr, role, bssid,
- ssid->ssid, ssid->ssid_len, 0, go_dev_addr, 1);
+ ssid->ssid, ssid->ssid_len, freq, go_dev_addr, 1);
}
@@ -4179,6 +4498,9 @@
struct wpa_ssid *ssid;
int persistent;
+ wpa_s->p2p_persistent_go_freq = 0;
+ wpa_s->p2p_go_ht40 = 0;
+
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
break;
@@ -4247,7 +4569,7 @@
}
if (!wpa_s->show_group_started || !ssid)
- return;
+ goto done;
wpa_s->show_group_started = 0;
@@ -4289,6 +4611,19 @@
if (network_id < 0)
network_id = ssid->id;
wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 1);
+
+done:
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after successful connection");
+ p2p_increase_search_delay(
+ wpa_s->global->p2p,
+ wpas_p2p_search_delay(wpa_s));
+ }
+ }
}
@@ -4344,8 +4679,7 @@
wpa_printf(MSG_DEBUG, "P2P: Group idle timeout reached - terminate "
"group");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_IDLE_TIMEOUT;
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_IDLE_TIMEOUT);
}
@@ -4384,7 +4718,7 @@
"during provisioning");
return;
}
-
+#ifndef ANDROID_P2P
if (wpa_s->show_group_started) {
/*
* Use the normal group formation timeout between the end of
@@ -4397,6 +4731,7 @@
"complete");
return;
}
+#endif
wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
timeout);
@@ -4405,14 +4740,15 @@
}
-void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len,
- int locally_generated)
+/* Returns 1 if the interface was removed */
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated)
{
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
- return;
+ return 0;
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
- return;
+ return 0;
if (!locally_generated)
p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie,
@@ -4424,9 +4760,13 @@
wpa_s->current_ssid->mode == WPAS_MODE_INFRA) {
wpa_printf(MSG_DEBUG, "P2P: GO indicated that the P2P Group "
"session is ending");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_GO_ENDING_SESSION;
- wpas_p2p_group_delete(wpa_s, 0);
+ if (wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_GO_ENDING_SESSION)
+ > 0)
+ return 1;
}
+
+ return 0;
}
@@ -4793,7 +5133,8 @@
found = 1;
eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
wpa_s->parent, NULL);
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s,
+ P2P_GROUP_REMOVAL_REQUESTED);
break;
}
}
@@ -4814,8 +5155,7 @@
wpa_printf(MSG_DEBUG, "P2P: Remove group due to driver resource not "
"being available anymore");
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
- wpas_p2p_group_delete(wpa_s, 0);
+ wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_UNAVAILABLE);
}
@@ -4861,10 +5201,8 @@
if (wpa_s == NULL)
return -1;
- wpa_s->removal_reason = P2P_GROUP_REMOVAL_REQUESTED;
- wpas_p2p_group_delete(wpa_s, 0);
-
- return 0;
+ return wpas_p2p_group_delete(wpa_s, P2P_GROUP_REMOVAL_REQUESTED) < 0 ?
+ -1 : 0;
}
@@ -4948,13 +5286,14 @@
wpa_s = wpa_s->parent;
offchannel_send_action_done(wpa_s);
if (group_added)
- wpas_p2p_group_delete(group, 1);
+ wpas_p2p_group_delete(group, P2P_GROUP_REMOVAL_SILENT);
wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Fall back to GO Negotiation");
wpas_p2p_connect(wpa_s, wpa_s->pending_join_dev_addr, wpa_s->p2p_pin,
wpa_s->p2p_wps_method, wpa_s->p2p_persistent_group, 0,
0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
- wpa_s->p2p_pd_before_go_neg);
+ wpa_s->p2p_pd_before_go_neg,
+ wpa_s->p2p_go_ht40);
}
@@ -4974,6 +5313,44 @@
return 1;
}
+
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s)
+{
+ const char *rn, *rn2;
+ struct wpa_supplicant *ifs;
+
+ if (wpa_s->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search delay due to "
+ "concurrent operation",
+ P2P_CONCURRENT_SEARCH_DELAY);
+ return P2P_CONCURRENT_SEARCH_DELAY;
+ }
+
+ if (!wpa_s->driver->get_radio_name)
+ return 0;
+ rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+ if (rn == NULL || rn[0] == '\0')
+ return 0;
+
+ for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+ if (ifs == wpa_s || !ifs->driver->get_radio_name)
+ continue;
+
+ rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+ if (!rn2 || os_strcmp(rn, rn2) != 0)
+ continue;
+ if (ifs->wpa_state > WPA_SCANNING) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use %u ms search "
+ "delay due to concurrent operation on "
+ "interface %s",
+ P2P_CONCURRENT_SEARCH_DELAY, ifs->ifname);
+ return P2P_CONCURRENT_SEARCH_DELAY;
+ }
+ }
+
+ return 0;
+}
+
#ifdef ANDROID_P2P
int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
{
@@ -5003,8 +5380,7 @@
* P2P connection. So remove the interface */
wpa_printf(MSG_DEBUG, "P2P: Removing P2P connection due to Single channel"
"concurrent mode frequency conflict");
- iface->removal_reason = P2P_GROUP_REMOVAL_FREQ_CONFLICT;
- wpas_p2p_group_delete(iface, 0);
+ wpas_p2p_group_delete(iface, P2P_GROUP_REMOVAL_FREQ_CONFLICT);
} else {
/* Existing connection has the priority. Disable the newly
* selected network and let the application know about it.
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 5af323f..6e4cc1d 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -21,7 +21,7 @@
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join,
int auth, int go_intent, int freq, int persistent_id,
- int pd);
+ int pd, int ht40);
void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration);
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
@@ -32,10 +32,10 @@
#endif
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq);
+ int freq, int ht40);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq);
+ int freq, int ht40);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
@@ -57,7 +57,7 @@
int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
enum p2p_discovery_type type,
unsigned int num_req_dev_types, const u8 *req_dev_types,
- const u8 *dev_id);
+ const u8 *dev_id, unsigned int search_delay);
void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
@@ -90,6 +90,8 @@
const struct wpabuf *tlvs);
u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
u8 version, const char *query);
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+ const u8 *dst, const char *role);
int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
const u8 *dst, u8 dialog_token,
@@ -110,7 +112,8 @@
const char *service);
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
- struct wpa_ssid *ssid, const u8 *go_dev_addr);
+ struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+ int ht40);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -118,9 +121,9 @@
u32 interval1, u32 duration2, u32 interval2);
int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
unsigned int interval);
-void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
- u16 reason_code, const u8 *ie, size_t ie_len,
- int locally_generated);
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+ u16 reason_code, const u8 *ie, size_t ie_len,
+ int locally_generated);
void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
u16 reason_code, const u8 *ie, size_t ie_len,
int locally_generated);
@@ -149,5 +152,8 @@
void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
const u8 *addr);
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel);
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
#endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 8df21d9..d8db81f 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -89,6 +89,9 @@
count++;
ssid = ssid->next;
}
+ if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+ wpa_s->conf->auto_interworking)
+ count++;
return count;
}
@@ -138,7 +141,7 @@
reslen = int_array_len(*res);
alen = int_array_len(a);
- n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
+ n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
if (n == NULL) {
os_free(*res);
*res = NULL;
@@ -385,9 +388,7 @@
#endif /* CONFIG_INTERWORKING */
-static struct wpabuf *
-wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
- struct wpa_driver_scan_params *params)
+static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
{
struct wpabuf *extra_ie = NULL;
#ifdef CONFIG_WPS
@@ -475,15 +476,18 @@
#ifdef CONFIG_P2P
if (wpas_p2p_in_progress(wpa_s)) {
- if (wpa_s->wpa_state == WPA_SCANNING) {
+ if (wpa_s->sta_scan_pending &&
+ wpas_p2p_in_progress(wpa_s) == 2 &&
+ wpa_s->p2p_cb_on_scan_complete) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
+ "mode scan during P2P search");
+ } else {
wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
"while P2P operation is in progress");
+ wpa_s->sta_scan_pending = 1;
wpa_supplicant_req_scan(wpa_s, 5, 0);
- } else {
- wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while "
- "P2P operation is in progress");
+ return;
}
- return;
}
#endif /* CONFIG_P2P */
@@ -642,7 +646,7 @@
#endif /* CONFIG_P2P */
wpa_supplicant_optimize_freqs(wpa_s, ¶ms);
- extra_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms);
+ extra_ie = wpa_supplicant_extra_ies(wpa_s);
#ifdef CONFIG_HS20
if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
@@ -771,7 +775,7 @@
struct wpa_driver_scan_params *scan_params;
enum wpa_states prev_state;
struct wpa_ssid *ssid = NULL;
- struct wpabuf *wps_ie = NULL;
+ struct wpabuf *extra_ie = NULL;
int ret;
unsigned int max_sched_scan_ssids;
int wildcard = 0;
@@ -935,8 +939,11 @@
params.filter_ssids = NULL;
}
- if (wpa_s->wps)
- wps_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms);
+ extra_ie = wpa_supplicant_extra_ies(wpa_s);
+ if (extra_ie) {
+ params.extra_ies = wpabuf_head(extra_ie);
+ params.extra_ies_len = wpabuf_len(extra_ie);
+ }
scan_params = ¶ms;
@@ -953,7 +960,7 @@
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
- wpabuf_free(wps_ie);
+ wpabuf_free(extra_ie);
os_free(params.filter_ssids);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index c7187e4..b09e5f1 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -127,6 +127,15 @@
"key management and encryption suites");
return;
}
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+ /*
+ * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+ * use non-WPA since the scan results did not indicate that the
+ * AP is using WPA or WPA2.
+ */
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_s->sme.assoc_req_ie_len = 0;
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -802,7 +811,7 @@
return;
}
- params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+ params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
if (params->freqs == NULL)
return;
for (count = 0, i = 0; i < mode->num_channels; i++) {
@@ -843,6 +852,8 @@
const u8 *ie;
struct wpa_bss *bss = wpa_s->current_bss;
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ struct hostapd_hw_modes *hw_mode = NULL;
+ int i;
eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
wpa_s->sme.sched_obss_scan = 0;
@@ -853,9 +864,20 @@
ssid->mode != IEEE80211_MODE_INFRA)
return; /* Not using station SME in wpa_supplicant */
- if (!wpa_s->hw.modes ||
- !(wpa_s->hw.modes->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
- return; /* Driver does not support HT40 */
+ if (!wpa_s->hw.modes)
+ return;
+
+ /* only HT caps in 11g mode are relevant */
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
+ hw_mode = &wpa_s->hw.modes[i];
+ if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G)
+ break;
+ }
+
+ /* Driver does not support HT40 for 11g or doesn't have 11g. */
+ if (i == wpa_s->hw.num_modes || !hw_mode ||
+ !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ return;
if (bss == NULL || bss->freq < 2400 || bss->freq > 2500)
return; /* Not associated on 2.4 GHz band */
@@ -938,9 +960,9 @@
sme_check_sa_query_timeout(wpa_s))
return;
- nbuf = os_realloc(wpa_s->sme.sa_query_trans_id,
- (wpa_s->sme.sa_query_count + 1) *
- WLAN_SA_QUERY_TR_ID_LEN);
+ nbuf = os_realloc_array(wpa_s->sme.sa_query_trans_id,
+ wpa_s->sme.sa_query_count + 1,
+ WLAN_SA_QUERY_TR_ID_LEN);
if (nbuf == NULL)
return;
if (wpa_s->sme.sa_query_count == 0) {
diff --git a/wpa_supplicant/tests/test_eap_sim_common.c b/wpa_supplicant/tests/test_eap_sim_common.c
index 4448858..f60b182 100644
--- a/wpa_supplicant/tests/test_eap_sim_common.c
+++ b/wpa_supplicant/tests/test_eap_sim_common.c
@@ -28,7 +28,7 @@
printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w) != 0)) {
+ if (memcmp(w, buf, sizeof(w)) != 0) {
printf("eap_sim_prf failed\n");
return 1;
}
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
new file mode 100644
index 0000000..92ca536
--- /dev/null
+++ b/wpa_supplicant/wifi_display.c
@@ -0,0 +1,251 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "p2p/p2p.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_supplicant_i.h"
+#include "wifi_display.h"
+
+
+int wifi_display_init(struct wpa_global *global)
+{
+ global->wifi_display = 1;
+ return 0;
+}
+
+
+void wifi_display_deinit(struct wpa_global *global)
+{
+ int i;
+ for (i = 0; i < MAX_WFD_SUBELEMS; i++) {
+ wpabuf_free(global->wfd_subelem[i]);
+ global->wfd_subelem[i] = NULL;
+ }
+}
+
+
+static int wifi_display_update_wfd_ie(struct wpa_global *global)
+{
+ struct wpabuf *ie, *buf;
+ size_t len, plen;
+
+ wpa_printf(MSG_DEBUG, "WFD: Update WFD IE");
+
+ if (!global->wifi_display) {
+ wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display disabled - do not "
+ "include WFD IE");
+ p2p_set_wfd_ie_beacon(global->p2p, NULL);
+ p2p_set_wfd_ie_probe_req(global->p2p, NULL);
+ p2p_set_wfd_ie_probe_resp(global->p2p, NULL);
+ p2p_set_wfd_ie_assoc_req(global->p2p, NULL);
+ p2p_set_wfd_ie_invitation(global->p2p, NULL);
+ p2p_set_wfd_ie_prov_disc_req(global->p2p, NULL);
+ p2p_set_wfd_ie_prov_disc_resp(global->p2p, NULL);
+ p2p_set_wfd_ie_go_neg(global->p2p, NULL);
+ p2p_set_wfd_dev_info(global->p2p, NULL);
+ p2p_set_wfd_assoc_bssid(global->p2p, NULL);
+ p2p_set_wfd_coupled_sink_info(global->p2p, NULL);
+ return 0;
+ }
+
+ p2p_set_wfd_dev_info(global->p2p,
+ global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ p2p_set_wfd_assoc_bssid(
+ global->p2p,
+ global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID]);
+ p2p_set_wfd_coupled_sink_info(
+ global->p2p, global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+ /*
+ * WFD IE is included in number of management frames. Two different
+ * sets of subelements are included depending on the frame:
+ *
+ * Beacon, (Re)Association Request, GO Negotiation Req/Resp/Conf,
+ * Provision Discovery Req:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ *
+ * Probe Request:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Extended Capability]
+ *
+ * Probe Response:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Extended Capability]
+ * [WFD Session Info]
+ *
+ * (Re)Association Response, P2P Invitation Req/Resp,
+ * Provision Discovery Resp:
+ * WFD Device Info
+ * [Associated BSSID]
+ * [Coupled Sink Info]
+ * [WFD Session Info]
+ */
+ len = 0;
+ if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_DEVICE_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_ASSOCIATED_BSSID]);
+ if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_COUPLED_SINK]);
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ len += wpabuf_len(global->wfd_subelem[
+ WFD_SUBELEM_SESSION_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+ len += wpabuf_len(global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
+
+ if (global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_DEVICE_INFO]);
+ if (global->wfd_subelem[WFD_SUBELEM_ASSOCIATED_BSSID])
+ wpabuf_put_buf(buf, global->wfd_subelem[
+ WFD_SUBELEM_ASSOCIATED_BSSID]);
+ if (global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_COUPLED_SINK]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Beacon", ie);
+ p2p_set_wfd_ie_beacon(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for (Re)Association Request",
+ ie);
+ p2p_set_wfd_ie_assoc_req(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for GO Negotiation", ie);
+ p2p_set_wfd_ie_go_neg(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+ "Request", ie);
+ p2p_set_wfd_ie_prov_disc_req(global->p2p, ie);
+
+ plen = buf->used;
+ if (global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_EXT_CAPAB]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Request", ie);
+ p2p_set_wfd_ie_probe_req(global->p2p, ie);
+
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Probe Response", ie);
+ p2p_set_wfd_ie_probe_resp(global->p2p, ie);
+
+ /* Remove WFD Extended Capability from buffer */
+ buf->used = plen;
+ if (global->wfd_subelem[WFD_SUBELEM_SESSION_INFO])
+ wpabuf_put_buf(buf,
+ global->wfd_subelem[WFD_SUBELEM_SESSION_INFO]);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for P2P Invitation", ie);
+ p2p_set_wfd_ie_invitation(global->p2p, ie);
+
+ ie = wifi_display_encaps(buf);
+ wpa_hexdump_buf(MSG_DEBUG, "WFD: WFD IE for Provision Discovery "
+ "Response", ie);
+ p2p_set_wfd_ie_prov_disc_resp(global->p2p, ie);
+
+ wpabuf_free(buf);
+
+ return 0;
+}
+
+
+void wifi_display_enable(struct wpa_global *global, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "WFD: Wi-Fi Display %s",
+ enabled ? "enabled" : "disabled");
+ global->wifi_display = enabled;
+ wifi_display_update_wfd_ie(global);
+}
+
+
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd)
+{
+ char *pos;
+ int subelem;
+ size_t len;
+ struct wpabuf *e;
+
+ pos = os_strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
+ len = os_strlen(pos);
+ if (len & 1)
+ return -1;
+ len /= 2;
+
+ if (len == 0) {
+ /* Clear subelement */
+ e = NULL;
+ wpa_printf(MSG_DEBUG, "WFD: Clear subelement %d", subelem);
+ } else {
+ e = wpabuf_alloc(1 + len);
+ if (e == NULL)
+ return -1;
+ wpabuf_put_u8(e, subelem);
+ if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+ wpabuf_free(e);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "WFD: Set subelement %d", subelem);
+ }
+
+ wpabuf_free(global->wfd_subelem[subelem]);
+ global->wfd_subelem[subelem] = e;
+ wifi_display_update_wfd_ie(global);
+
+ return 0;
+}
+
+
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+ char *buf, size_t buflen)
+{
+ int subelem;
+
+ subelem = atoi(cmd);
+ if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+ return -1;
+
+ if (global->wfd_subelem[subelem] == NULL)
+ return 0;
+
+ return wpa_snprintf_hex(buf, buflen,
+ wpabuf_head_u8(global->wfd_subelem[subelem]) +
+ 1,
+ wpabuf_len(global->wfd_subelem[subelem]) - 1);
+}
diff --git a/wpa_supplicant/wifi_display.h b/wpa_supplicant/wifi_display.h
new file mode 100644
index 0000000..b75d4f2
--- /dev/null
+++ b/wpa_supplicant/wifi_display.h
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WIFI_DISPLAY_H
+#define WIFI_DISPLAY_H
+
+int wifi_display_init(struct wpa_global *global);
+void wifi_display_deinit(struct wpa_global *global);
+void wifi_display_enable(struct wpa_global *global, int enabled);
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+ char *buf, size_t buflen);
+
+#endif /* WIFI_DISPLAY_H */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
new file mode 100644
index 0000000..98ce966
--- /dev/null
+++ b/wpa_supplicant/wnm_sta.c
@@ -0,0 +1,248 @@
+/*
+ * wpa_supplicant - WNM
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "rsn_supp/wpa.h"
+#include "../wpa_supplicant/wpa_supplicant_i.h"
+#include "../wpa_supplicant/driver_i.h"
+
+#define MAX_TFS_IE_LEN 1024
+
+#ifdef CONFIG_IEEE80211V
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct wpa_supplicant *wpa_s, u8 *buf,
+ u16 *buf_len, enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+ return wpa_drv_wnm_oper(wpa_s, oper, wpa_s->bssid, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct wpa_supplicant *wpa_s,
+ const u8 *addr, u8 *buf, u16 *buf_len,
+ enum wnm_oper oper)
+{
+ wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+ return wpa_drv_wnm_oper(wpa_s, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.request */
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+ u8 action, u8 intval)
+{
+ struct ieee80211_mgmt *mgmt;
+ int res;
+ size_t len;
+ struct wnm_sleep_element *wnmsleep_ie;
+ u8 *wnmtfs_ie;
+ u8 wnmsleep_ie_len;
+ u16 wnmtfs_ie_len; /* possibly multiple IE(s) */
+ enum wnm_oper tfs_oper = action == 0 ? WNM_SLEEP_TFS_REQ_IE_ADD :
+ WNM_SLEEP_TFS_REQ_IE_NONE;
+
+ /* WNM-Sleep Mode IE */
+ wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+ wnmsleep_ie = os_zalloc(sizeof(struct wnm_sleep_element));
+ if (wnmsleep_ie == NULL)
+ return -1;
+ wnmsleep_ie->eid = WLAN_EID_WNMSLEEP;
+ wnmsleep_ie->len = wnmsleep_ie_len - 2;
+ wnmsleep_ie->action_type = action;
+ wnmsleep_ie->status = WNM_STATUS_SLEEP_ACCEPT;
+ wnmsleep_ie->intval = intval;
+
+ /* TFS IE(s) */
+ wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+ if (wnmtfs_ie == NULL) {
+ os_free(wnmsleep_ie);
+ return -1;
+ }
+ if (ieee80211_11_get_tfs_ie(wpa_s, wnmtfs_ie, &wnmtfs_ie_len,
+ tfs_oper)) {
+ wnmtfs_ie_len = 0;
+ os_free(wnmtfs_ie);
+ wnmtfs_ie = NULL;
+ }
+
+ mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len + wnmtfs_ie_len);
+ if (mgmt == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+ "WNM-Sleep Request action frame");
+ return -1;
+ }
+
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ mgmt->u.action.category = WLAN_ACTION_WNM;
+ mgmt->u.action.u.wnm_sleep_req.action = WNM_SLEEP_MODE_REQ;
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable, wnmsleep_ie,
+ wnmsleep_ie_len);
+ /* copy TFS IE here */
+ if (wnmtfs_ie_len > 0) {
+ os_memcpy(mgmt->u.action.u.wnm_sleep_req.variable +
+ wnmsleep_ie_len, wnmtfs_ie, wnmtfs_ie_len);
+ }
+
+ len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_req) + wnmsleep_ie_len +
+ wnmtfs_ie_len;
+
+ res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+ wpa_s->own_addr, wpa_s->bssid,
+ &mgmt->u.action.category, len, 0);
+ if (res < 0)
+ wpa_printf(MSG_DEBUG, "Failed to send WNM-Sleep Request "
+ "(action=%d, intval=%d)", action, intval);
+
+ os_free(wnmsleep_ie);
+ os_free(wnmtfs_ie);
+ os_free(mgmt);
+
+ return res;
+}
+
+
+static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
+ const u8 *frm, int len)
+{
+ /*
+ * Action [1] | Diaglog Token [1] | Key Data Len [2] | Key Data |
+ * WNM-Sleep Mode IE | TFS Response IE
+ */
+ u8 *pos = (u8 *) frm; /* point to action field */
+ u16 key_len_total = le_to_host16(*((u16 *)(frm+2)));
+ u8 gtk_len;
+#ifdef CONFIG_IEEE80211W
+ u8 igtk_len;
+#endif /* CONFIG_IEEE80211W */
+ struct wnm_sleep_element *wnmsleep_ie = NULL;
+ /* multiple TFS Resp IE (assuming consecutive) */
+ u8 *tfsresp_ie_start = NULL;
+ u8 *tfsresp_ie_end = NULL;
+ u16 tfsresp_ie_len = 0;
+
+ wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d",
+ frm[0], frm[1], key_len_total);
+ pos += 4 + key_len_total;
+ while (pos - frm < len) {
+ u8 ie_len = *(pos + 1);
+ if (*pos == WLAN_EID_WNMSLEEP)
+ wnmsleep_ie = (struct wnm_sleep_element *) pos;
+ else if (*pos == WLAN_EID_TFS_RESP) {
+ if (!tfsresp_ie_start)
+ tfsresp_ie_start = pos;
+ tfsresp_ie_end = pos;
+ } else
+ wpa_printf(MSG_DEBUG, "EID %d not recognized", *pos);
+ pos += ie_len + 2;
+ }
+
+ if (!wnmsleep_ie) {
+ wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+ return;
+ }
+
+ if (wnmsleep_ie->status == WNM_STATUS_SLEEP_ACCEPT) {
+ wpa_printf(MSG_DEBUG, "Successfully recv WNM-Sleep Response "
+ "frame (action=%d, intval=%d)",
+ wnmsleep_ie->action_type, wnmsleep_ie->intval);
+ if (wnmsleep_ie->action_type == 0) {
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_CONFIRM,
+ wpa_s->bssid, NULL, NULL);
+ /* remove GTK/IGTK ?? */
+
+ /* set the TFS Resp IE(s) */
+ if (tfsresp_ie_start && tfsresp_ie_end &&
+ tfsresp_ie_end - tfsresp_ie_start >= 0) {
+ tfsresp_ie_len = (tfsresp_ie_end +
+ tfsresp_ie_end[1] + 2) -
+ tfsresp_ie_start;
+ wpa_printf(MSG_DEBUG, "TFS Resp IE(s) found");
+ /*
+ * pass the TFS Resp IE(s) to driver for
+ * processing
+ */
+ if (ieee80211_11_set_tfs_ie(
+ wpa_s, wpa_s->bssid,
+ tfsresp_ie_start,
+ &tfsresp_ie_len,
+ WNM_SLEEP_TFS_RESP_IE_SET))
+ wpa_printf(MSG_DEBUG, "Fail to set "
+ "TFS Resp IE");
+ }
+ } else if (wnmsleep_ie->action_type == 1) {
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_CONFIRM,
+ wpa_s->bssid, NULL, NULL);
+ /* Install GTK/IGTK */
+ do {
+ /* point to key data field */
+ u8 *ptr = (u8 *) frm + 1 + 1 + 2;
+ while (ptr < (u8 *) frm + 4 + key_len_total) {
+ if (*ptr == WNM_SLEEP_SUBELEM_GTK) {
+ gtk_len = *(ptr + 4);
+ wpa_wnmsleep_install_key(
+ wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_GTK,
+ ptr);
+ ptr += 13 + gtk_len;
+#ifdef CONFIG_IEEE80211W
+ } else if (*ptr ==
+ WNM_SLEEP_SUBELEM_IGTK) {
+ igtk_len = WPA_IGTK_LEN;
+ wpa_wnmsleep_install_key(
+ wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_IGTK,
+ ptr);
+ ptr += 10 + WPA_IGTK_LEN;
+#endif /* CONFIG_IEEE80211W */
+ } else
+ break; /* skip the loop */
+ }
+ } while(0);
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "Reject recv WNM-Sleep Response frame "
+ "(action=%d, intval=%d)",
+ wnmsleep_ie->action_type, wnmsleep_ie->intval);
+ if (wnmsleep_ie->action_type == 0)
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_ENTER_FAIL,
+ wpa_s->bssid, NULL, NULL);
+ else if (wnmsleep_ie->action_type == 1)
+ wpa_drv_wnm_oper(wpa_s, WNM_SLEEP_EXIT_FAIL,
+ wpa_s->bssid, NULL, NULL);
+ }
+}
+
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+ struct rx_action *action)
+{
+ u8 *pos = (u8 *) action->data; /* point to action field */
+ u8 act = *pos++;
+ /* u8 dialog_token = *pos++; */
+
+ switch (act) {
+ case WNM_SLEEP_MODE_RESP:
+ ieee802_11_rx_wnmsleep_resp(wpa_s, action->data, action->len);
+ break;
+ default:
+ break;
+ }
+}
+
+#endif /* CONFIG_IEEE80211V */
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
new file mode 100644
index 0000000..ba2535b
--- /dev/null
+++ b/wpa_supplicant/wnm_sta.h
@@ -0,0 +1,21 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_STA_H
+#define WNM_STA_H
+
+struct rx_action;
+struct wpa_supplicant;
+
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+ u8 action, u8 intval);
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+ struct rx_action *action);
+
+#endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index a8e8488..3986b9b 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -95,8 +95,11 @@
static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
-static void print_help(void);
+static void print_help(const char *cmd);
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
+static void wpa_cli_close_connection(void);
+static char * wpa_cli_get_default_ifname(void);
+static char ** wpa_list_cmd_list(void);
static void usage(void)
@@ -113,7 +116,7 @@
" -B = run a daemon in the background\n"
" default path: " CONFIG_CTRL_IFACE_DIR "\n"
" default interface: first interface found in socket path\n");
- print_help();
+ print_help(NULL);
}
@@ -241,7 +244,7 @@
char **res;
struct cli_txt_entry *e;
- res = os_zalloc((count + 1) * sizeof(char *));
+ res = os_calloc(count + 1, sizeof(char *));
if (res == NULL)
return NULL;
@@ -364,6 +367,7 @@
} else {
printf("Warning: Failed to attach to "
"wpa_supplicant.\n");
+ wpa_cli_close_connection();
return -1;
}
}
@@ -456,6 +460,58 @@
}
+static int write_cmd(char *buf, size_t buflen, const char *cmd, int argc,
+ char *argv[])
+{
+ int i, res;
+ char *pos, *end;
+
+ pos = buf;
+ end = buf + buflen;
+
+ res = os_snprintf(pos, end - pos, "%s", cmd);
+ if (res < 0 || res >= end - pos)
+ goto fail;
+ pos += res;
+
+ for (i = 0; i < argc; i++) {
+ res = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (res < 0 || res >= end - pos)
+ goto fail;
+ pos += res;
+ }
+
+ buf[buflen - 1] = '\0';
+ return 0;
+
+fail:
+ printf("Too long command\n");
+ return -1;
+}
+
+
+static int wpa_cli_cmd(struct wpa_ctrl *ctrl, const char *cmd, int min_args,
+ int argc, char *argv[])
+{
+ char buf[256];
+ if (argc < min_args) {
+ printf("Invalid %s command - at least %d argument%s "
+ "required.\n", cmd, min_args,
+ min_args > 1 ? "s are" : " is");
+ return -1;
+ }
+ if (write_cmd(buf, sizeof(buf), cmd, argc, argv) < 0)
+ return -1;
+ return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int wpa_cli_cmd_ifname(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "IFNAME");
+}
+
+
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
@@ -480,14 +536,7 @@
static int wpa_cli_cmd_note(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int ret;
- if (argc == 0)
- return -1;
- ret = os_snprintf(cmd, sizeof(cmd), "NOTE %s", argv[0]);
- if (ret < 0 || (size_t) ret >= sizeof(cmd))
- return -1;
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "NOTE", 1, argc, argv);
}
@@ -505,11 +554,26 @@
static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- print_help();
+ print_help(argc > 0 ? argv[0] : NULL);
return 0;
}
+static char ** wpa_cli_complete_help(const char *str, int pos)
+{
+ int arg = get_cmd_arg_num(str, pos);
+ char **res = NULL;
+
+ switch (arg) {
+ case 1:
+ res = wpa_list_cmd_list();
+ break;
+ }
+
+ return res;
+}
+
+
static int wpa_cli_cmd_license(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
printf("%s\n\n%s\n", wpa_cli_version, wpa_cli_full_license);
@@ -577,21 +641,7 @@
static int wpa_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid GET command: need one argument (variable "
- "name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long GET command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET", 1, argc, argv);
}
@@ -617,97 +667,48 @@
static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid PREAUTH command: needs one argument "
- "(BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long PREAUTH command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "PREAUTH", 1, argc, argv);
}
static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid AP_SCAN command: needs one argument (ap_scan "
- "value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long AP_SCAN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "AP_SCAN", 1, argc, argv);
}
static int wpa_cli_cmd_scan_interval(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid SCAN_INTERVAL command: needs one argument "
- "scan_interval value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "SCAN_INTERVAL %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SCAN_INTERVAL command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SCAN_INTERVAL", 1, argc, argv);
}
static int wpa_cli_cmd_bss_expire_age(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid BSS_EXPIRE_AGE command: needs one argument "
- "(bss_expire_age value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_AGE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long BSS_EXPIRE_AGE command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS_EXPIRE_AGE", 1, argc, argv);
}
static int wpa_cli_cmd_bss_expire_count(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
+ return wpa_cli_cmd(ctrl, "BSS_EXPIRE_COUNT", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_bss_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
char cmd[256];
int res;
- if (argc != 1) {
- printf("Invalid BSS_EXPIRE_COUNT command: needs one argument "
- "(bss_expire_count value)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "BSS_EXPIRE_COUNT %s", argv[0]);
+ if (argc < 1)
+ res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
+ else
+ res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long BSS_EXPIRE_COUNT command.\n");
+ printf("Too long BSS_FLUSH command.\n");
return -1;
}
return wpa_ctrl_command(ctrl, cmd);
@@ -717,69 +718,24 @@
static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid STKSTART command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long STKSTART command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "STKSTART", 1, argc, argv);
}
static int wpa_cli_cmd_ft_ds(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid FT_DS command: needs one argument "
- "(Target AP MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long FT_DS command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "FT_DS", 1, argc, argv);
}
static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc == 0) {
- /* Any BSSID */
- return wpa_ctrl_command(ctrl, "WPS_PBC");
- }
-
- /* Specific BSSID */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PBC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_PBC", 0, argc, argv);
}
static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
printf("Invalid WPS_PIN command: need one or two arguments:\n"
"- BSSID: use 'any' to select any\n"
@@ -788,49 +744,14 @@
return -1;
}
- if (argc == 1) {
- /* Use dynamically generated PIN (returned as reply) */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
- }
-
- /* Use hardcoded PIN from a label */
- res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_PIN", 1, argc, argv);
}
static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1 && argc != 2) {
- printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
- "- PIN to be verified\n");
- return -1;
- }
-
- if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_CHECK_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_CHECK_PIN", 1, argc, argv);
}
@@ -844,9 +765,6 @@
#ifdef CONFIG_WPS_OOB
static int wpa_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 3 && argc != 4) {
printf("Invalid WPS_OOB command: need three or four "
"arguments:\n"
@@ -859,17 +777,7 @@
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_OOB %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_OOB command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_OOB", 3, argc, argv);
}
#endif /* CONFIG_WPS_OOB */
@@ -878,43 +786,14 @@
static int wpa_cli_cmd_wps_nfc(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc >= 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC %s",
- argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC");
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_NFC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_NFC", 0, argc, argv);
}
static int wpa_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid WPS_NFC_TOKEN command: need one argument:\n"
- "format: WPS or NDEF\n");
- return -1;
- }
- if (argc >= 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s",
- argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN");
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_NFC_TOKEN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_NFC_TOKEN", 1, argc, argv);
}
@@ -1006,41 +885,14 @@
static int wpa_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc < 1) {
- printf("Invalid WPS_AP_PIN command: needs at least one "
- "argument\n");
- return -1;
- }
-
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_AP_PIN %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_AP_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_AP_PIN", 1, argc, argv);
}
static int wpa_cli_cmd_wps_er_start(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- if (argc > 0) {
- os_snprintf(cmd, sizeof(cmd), "WPS_ER_START %s", argv[0]);
- return wpa_ctrl_command(ctrl, cmd);
- }
- return wpa_ctrl_command(ctrl, "WPS_ER_START");
+ return wpa_cli_cmd(ctrl, "WPS_ER_START", 0, argc, argv);
}
@@ -1055,9 +907,6 @@
static int wpa_cli_cmd_wps_er_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc < 2) {
printf("Invalid WPS_ER_PIN command: need at least two "
"arguments:\n"
@@ -1067,48 +916,20 @@
return -1;
}
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PIN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_PIN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_PIN", 2, argc, argv);
}
static int wpa_cli_cmd_wps_er_pbc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid WPS_ER_PBC command: need one argument:\n"
- "- UUID: Specify the Enrollee\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_PBC %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_PBC command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_PBC", 1, argc, argv);
}
static int wpa_cli_cmd_wps_er_learn(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_LEARN command: need two arguments:\n"
"- UUID: specify which AP to use\n"
@@ -1116,22 +937,13 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_LEARN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_LEARN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_LEARN", 2, argc, argv);
}
static int wpa_cli_cmd_wps_er_set_config(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_SET_CONFIG command: need two "
"arguments:\n"
@@ -1140,13 +952,7 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_SET_CONFIG %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_SET_CONFIG command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_SET_CONFIG", 2, argc, argv);
}
@@ -1205,9 +1011,6 @@
static int wpa_cli_cmd_wps_er_nfc_config_token(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 2) {
printf("Invalid WPS_ER_NFC_CONFIG_TOKEN command: need two "
"arguments:\n"
@@ -1216,53 +1019,20 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "WPS_ER_NFC_CONFIG_TOKEN %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long WPS_ER_NFC_CONFIG_TOKEN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "WPS_ER_NFC_CONFIG_TOKEN", 2, argc, argv);
}
#endif /* CONFIG_WPS_NFC */
static int wpa_cli_cmd_ibss_rsn(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid IBSS_RSN command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "IBSS_RSN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long IBSS_RSN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "IBSS_RSN", 1, argc, argv);
}
static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid LEVEL command: needs one argument (debug "
- "level)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long LEVEL command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "LEVEL", 1, argc, argv);
}
@@ -1467,85 +1237,25 @@
static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
if (argc < 2) {
printf("Invalid BSSID command: needs two arguments (network "
"id and BSSID)\n");
return -1;
}
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "BSSID");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BSSID command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BSSID command.\n");
- return -1;
- }
- pos += ret;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSSID", 2, argc, argv);
}
static int wpa_cli_cmd_blacklist(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "BLACKLIST");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BLACKLIST command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long BLACKLIST command.\n");
- return -1;
- }
- pos += ret;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BLACKLIST", 0, argc, argv);
}
static int wpa_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256], *pos, *end;
- int i, ret;
-
- end = cmd + sizeof(cmd);
- pos = cmd;
- ret = os_snprintf(pos, end - pos, "LOG_LEVEL");
- if (ret < 0 || ret >= end - pos) {
- printf("Too long LOG_LEVEL command.\n");
- return -1;
- }
- pos += ret;
- for (i = 0; i < argc; i++) {
- ret = os_snprintf(pos, end - pos, " %s", argv[i]);
- if (ret < 0 || ret >= end - pos) {
- printf("Too long LOG_LEVEL command.\n");
- return -1;
- }
- pos += ret;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "LOG_LEVEL", 0, argc, argv);
}
@@ -1559,68 +1269,21 @@
static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid SELECT_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SELECT_NETWORK", 1, argc, argv);
}
static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid ENABLE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "ENABLE_NETWORK", 1, argc, argv);
}
static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid DISABLE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "DISABLE_NETWORK", 1, argc, argv);
}
@@ -1634,21 +1297,7 @@
static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid REMOVE_NETWORK command: needs one argument "
- "(network id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "REMOVE_NETWORK", 1, argc, argv);
}
@@ -1676,9 +1325,6 @@
static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
wpa_cli_show_network_variables();
return 0;
@@ -1690,22 +1336,13 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
- argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET_NETWORK command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SET_NETWORK", 3, argc, argv);
}
static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0) {
wpa_cli_show_network_variables();
return 0;
@@ -1717,13 +1354,7 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long GET_NETWORK command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET_NETWORK", 2, argc, argv);
}
@@ -1743,42 +1374,19 @@
static int wpa_cli_cmd_remove_cred(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[32];
- int res;
-
- if (argc < 1) {
- printf("Invalid REMOVE_CRED command: needs one argument "
- "(cred id)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "REMOVE_CRED %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "REMOVE_CRED", 1, argc, argv);
}
static int wpa_cli_cmd_set_cred(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc != 3) {
printf("Invalid SET_CRED command: needs three arguments\n"
"(cred id, variable name, and value)\n");
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "SET_CRED %s %s %s",
- argv[0], argv[1], argv[2]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long SET_CRED command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "SET_CRED", 3, argc, argv);
}
@@ -1818,24 +1426,7 @@
static int wpa_cli_cmd_bss(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[64];
- int res;
-
- if (argc < 1) {
- printf("Invalid BSS command: need at least one argument"
- "(index or BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "BSS %s%s%s%s%s", argv[0],
- argc > 1 ? " " : "", argc > 1 ? argv[1] : "",
- argc > 2 ? " " : "", argc > 2 ? argv[2] : "");
-
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "BSS", 1, argc, argv);
}
@@ -1857,9 +1448,6 @@
static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[64];
- int res;
-
if (argc < 1 || argc > 2) {
printf("Invalid GET_CAPABILITY command: need either one or "
"two arguments\n");
@@ -1872,13 +1460,7 @@
return -1;
}
- res = os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
- (argc == 2) ? " strict" : "");
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "GET_CAPABILITY", 1, argc, argv);
}
@@ -1958,20 +1540,7 @@
static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid INTERFACE_REMOVE command: needs one argument "
- "(interface name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERFACE_REMOVE", 1, argc, argv);
}
@@ -1985,14 +1554,7 @@
#ifdef CONFIG_AP
static int wpa_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char buf[64];
- if (argc != 1) {
- printf("Invalid 'sta' command - exactly one argument, STA "
- "address, is required.\n");
- return -1;
- }
- os_snprintf(buf, sizeof(buf), "STA %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "STA", 1, argc, argv);
}
@@ -2049,36 +1611,14 @@
static int wpa_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char buf[64];
- if (argc < 1) {
- printf("Invalid 'deauthenticate' command - exactly one "
- "argument, STA address, is required.\n");
- return -1;
- }
- if (argc > 1)
- os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
- argv[0], argv[1]);
- else
- os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "DEAUTHENTICATE", 1, argc, argv);
}
static int wpa_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char buf[64];
- if (argc < 1) {
- printf("Invalid 'disassociate' command - exactly one "
- "argument, STA address, is required.\n");
- return -1;
- }
- if (argc > 1)
- os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
- argv[0], argv[1]);
- else
- os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "DISASSOCIATE", 1, argc, argv);
}
#endif /* CONFIG_AP */
@@ -2103,21 +1643,7 @@
static int wpa_cli_cmd_roam(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid ROAM command: needs one argument "
- "(target AP's BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "ROAM %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long ROAM command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "ROAM", 1, argc, argv);
}
@@ -2125,24 +1651,36 @@
static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[128];
- int res;
+ return wpa_cli_cmd(ctrl, "P2P_FIND", 0, argc, argv);
+}
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_FIND");
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_FIND %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static char ** wpa_cli_complete_p2p_find(const char *str, int pos)
+{
+ char **res = NULL;
+ int arg = get_cmd_arg_num(str, pos);
+
+ res = os_calloc(6, sizeof(char *));
+ if (res == NULL)
+ return NULL;
+ res[0] = os_strdup("type=social");
+ if (res[0] == NULL) {
+ os_free(res);
+ return NULL;
+ }
+ res[1] = os_strdup("type=progressive");
+ if (res[1] == NULL)
+ return res;
+ res[2] = os_strdup("delay=");
+ if (res[2] == NULL)
+ return res;
+ res[3] = os_strdup("dev_id=");
+ if (res[3] == NULL)
+ return res;
+ if (arg == 1)
+ res[4] = os_strdup("[timeout]");
+
+ return res;
}
@@ -2156,40 +1694,7 @@
static int wpa_cli_cmd_p2p_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc < 2) {
- printf("Invalid P2P_CONNECT command: needs at least two "
- "arguments (address and pbc/PIN)\n");
- return -1;
- }
-#ifdef ANDROID_P2P
- if (argc > 5)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_CONNECT %s %s %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3],
- argv[4], argv[5]);
- else
-#endif
- if (argc > 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_CONNECT %s %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3],
- argv[4]);
- else if (argc > 3)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_CONNECT %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_CONNECT", 2, argc, argv);
}
@@ -2211,37 +1716,14 @@
static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_LISTEN");
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_LISTEN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_LISTEN", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_group_remove(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_GROUP_REMOVE command: needs one argument "
- "(interface name)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_REMOVE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_REMOVE", 1, argc, argv);
}
@@ -2263,31 +1745,13 @@
static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "P2P_GROUP_ADD");
-
- if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_GROUP_ADD %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_GROUP_ADD", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_prov_disc(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[128];
- int res;
-
if (argc != 2 && argc != 3) {
printf("Invalid P2P_PROV_DISC command: needs at least "
"two arguments, address and config method\n"
@@ -2295,16 +1759,7 @@
return -1;
}
- if (argc == 3)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s",
- argv[0], argv[1], argv[2]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_PROV_DISC", 2, argc, argv);
}
@@ -2319,7 +1774,6 @@
char *argv[])
{
char cmd[4096];
- int res;
if (argc != 2 && argc != 4) {
printf("Invalid P2P_SERV_DISC_REQ command: needs two "
@@ -2329,16 +1783,8 @@
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_SERV_DISC_REQ %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
+ if (write_cmd(cmd, sizeof(cmd), "P2P_SERV_DISC_REQ", argc, argv) < 0)
return -1;
- cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -2346,21 +1792,7 @@
static int wpa_cli_cmd_p2p_serv_disc_cancel_req(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_SERV_DISC_CANCEL_REQ command: needs one "
- "argument (pending request identifier)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_CANCEL_REQ %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_CANCEL_REQ", 1, argc, argv);
}
@@ -2395,21 +1827,7 @@
static int wpa_cli_cmd_p2p_serv_disc_external(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_SERV_DISC_EXTERNAL command: needs one "
- "argument (external processing: 0/1)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_EXTERNAL %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SERV_DISC_EXTERNAL", 1, argc, argv);
}
@@ -2477,60 +1895,20 @@
static int wpa_cli_cmd_p2p_reject(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_REJECT command: needs one argument "
- "(peer address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_REJECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_REJECT", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_invite(struct wpa_ctrl *ctrl,
int argc, char *argv[])
{
- char cmd[128];
- int res;
-
- if (argc < 1) {
- printf("Invalid P2P_INVITE command: needs at least one "
- "argument\n");
- return -1;
- }
-
- if (argc > 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s %s",
- argv[0], argv[1], argv[2]);
- else if (argc > 1)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_INVITE %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_INVITE", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_peer(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char buf[64];
- if (argc != 1) {
- printf("Invalid 'p2p_peer' command - exactly one argument, "
- "P2P peer device address, is required.\n");
- return -1;
- }
- os_snprintf(buf, sizeof(buf), "P2P_PEER %s", argv[0]);
- return wpa_ctrl_command(ctrl, buf);
+ return wpa_cli_cmd(ctrl, "P2P_PEER", 1, argc, argv);
}
@@ -2606,20 +1984,7 @@
static int wpa_cli_cmd_p2p_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc != 2) {
- printf("Invalid P2P_SET command: needs two arguments (field, "
- "value)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_SET %s %s", argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_SET", 2, argc, argv);
}
@@ -2639,31 +2004,13 @@
static int wpa_cli_cmd_p2p_unauthorize(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc != 1) {
- printf("Invalid P2P_UNAUTHORIZE command: needs one argument "
- "(peer address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "P2P_UNAUTHORIZE %s", argv[0]);
-
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
-
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_UNAUTHORIZE", 1, argc, argv);
}
static int wpa_cli_cmd_p2p_presence_req(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
if (argc != 0 && argc != 2 && argc != 4) {
printf("Invalid P2P_PRESENCE_REQ command: needs two arguments "
"(preferred duration, interval; in microsecods).\n"
@@ -2672,28 +2019,13 @@
return -1;
}
- if (argc == 4)
- res = os_snprintf(cmd, sizeof(cmd),
- "P2P_PRESENCE_REQ %s %s %s %s",
- argv[0], argv[1], argv[2], argv[3]);
- else if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_PRESENCE_REQ");
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "P2P_PRESENCE_REQ", 0, argc, argv);
}
static int wpa_cli_cmd_p2p_ext_listen(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
if (argc != 0 && argc != 2) {
printf("Invalid P2P_EXT_LISTEN command: needs two arguments "
"(availability period, availability interval; in "
@@ -2703,18 +2035,54 @@
return -1;
}
- if (argc == 2)
- res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN %s %s",
- argv[0], argv[1]);
- else
- res = os_snprintf(cmd, sizeof(cmd), "P2P_EXT_LISTEN");
+ return wpa_cli_cmd(ctrl, "P2P_EXT_LISTEN", 0, argc, argv);
+}
+
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+
+static int wpa_cli_cmd_wfd_subelem_set(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[100];
+ int res;
+
+ if (argc != 1 && argc != 2) {
+ printf("Invalid WFD_SUBELEM_SET command: needs one or two "
+ "arguments (subelem, hexdump)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
+ argv[0], argc > 1 ? argv[1] : "");
if (res < 0 || (size_t) res >= sizeof(cmd))
return -1;
cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
-#endif /* CONFIG_P2P */
+
+static int wpa_cli_cmd_wfd_subelem_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[100];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid WFD_SUBELEM_GET command: needs one "
+ "argument (subelem)\n");
+ return -1;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
+ argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd))
+ return -1;
+ cmd[sizeof(cmd) - 1] = '\0';
+ return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
@@ -2735,58 +2103,34 @@
static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc == 0)
- return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERWORKING_SELECT", 0, argc, argv);
}
static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc != 1) {
- printf("Invalid INTERWORKING_CONNECT commands: needs one "
- "argument (BSSID)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s",
- argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "INTERWORKING_CONNECT", 1, argc, argv);
}
static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[100];
- int res;
+ return wpa_cli_cmd(ctrl, "ANQP_GET", 2, argc, argv);
+}
- if (argc != 2) {
- printf("Invalid ANQP_GET command: needs two arguments "
- "(addr and info id list)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+static int wpa_cli_cmd_gas_request(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "GAS_REQUEST", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_gas_response_get(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_cli_cmd(ctrl, "GAS_RESPONSE_GET", 2, argc, argv);
}
#endif /* CONFIG_INTERWORKING */
@@ -2796,21 +2140,7 @@
static int wpa_cli_cmd_hs20_anqp_get(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[100];
- int res;
-
- if (argc != 2) {
- printf("Invalid HS20_ANQP_GET command: needs two arguments "
- "(addr and subtype list)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "HS20_ANQP_GET %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd))
- return -1;
- cmd[sizeof(cmd) - 1] = '\0';
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "HS20_ANQP_GET", 2, argc, argv);
}
@@ -2818,7 +2148,6 @@
char *argv[])
{
char cmd[512];
- int res;
if (argc == 0) {
printf("Command needs one or two arguments (dst mac addr and "
@@ -2826,18 +2155,9 @@
return -1;
}
- if (argc == 1)
- res = os_snprintf(cmd, sizeof(cmd),
- "HS20_GET_NAI_HOME_REALM_LIST %s",
- argv[0]);
- else
- res = os_snprintf(cmd, sizeof(cmd),
- "HS20_GET_NAI_HOME_REALM_LIST %s %s",
- argv[0], argv[1]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long command.\n");
+ if (write_cmd(cmd, sizeof(cmd), "HS20_GET_NAI_HOME_REALM_LIST",
+ argc, argv) < 0)
return -1;
- }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -2848,83 +2168,28 @@
static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid STA_AUTOCONNECT command: needs one argument "
- "(0/1 = disable/enable automatic reconnection)\n");
- return -1;
- }
- res = os_snprintf(cmd, sizeof(cmd), "STA_AUTOCONNECT %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long STA_AUTOCONNECT command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "STA_AUTOCONNECT", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_discover(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_DISCOVER command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_DISCOVER %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_DISCOVER command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_DISCOVER", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_setup(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_SETUP command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_SETUP %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_SETUP command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_SETUP", 1, argc, argv);
}
static int wpa_cli_cmd_tdls_teardown(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
- char cmd[256];
- int res;
-
- if (argc != 1) {
- printf("Invalid TDLS_TEARDOWN command: needs one argument "
- "(Peer STA MAC address)\n");
- return -1;
- }
-
- res = os_snprintf(cmd, sizeof(cmd), "TDLS_TEARDOWN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long TDLS_TEARDOWN command.\n");
- return -1;
- }
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "TDLS_TEARDOWN", 1, argc, argv);
}
@@ -2953,24 +2218,23 @@
static int wpa_cli_cmd_autoscan(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- char cmd[256];
- int res;
-
if (argc == 0)
return wpa_ctrl_command(ctrl, "AUTOSCAN ");
- res = os_snprintf(cmd, sizeof(cmd), "AUTOSCAN %s", argv[0]);
- if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
- printf("Too long AUTOSCAN command.\n");
- return -1;
- }
-
- return wpa_ctrl_command(ctrl, cmd);
+ return wpa_cli_cmd(ctrl, "AUTOSCAN", 0, argc, argv);
}
#endif /* CONFIG_AUTOSCAN */
+static int wpa_cli_cmd_raw(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ if (argc == 0)
+ return -1;
+ return wpa_cli_cmd(ctrl, argv[0], 0, argc - 1, &argv[1]);
+}
+
+
#ifdef ANDROID
static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
@@ -2992,6 +2256,7 @@
}
#endif
+
enum wpa_cli_cmd_flags {
cli_cmd_flag_none = 0x00,
cli_cmd_flag_sensitive = 0x01
@@ -3000,398 +2265,433 @@
struct wpa_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+ char ** (*completion)(const char *str, int pos);
enum wpa_cli_cmd_flags flags;
const char *usage;
};
static struct wpa_cli_cmd wpa_cli_commands[] = {
- { "status", wpa_cli_cmd_status,
+ { "status", wpa_cli_cmd_status, NULL,
cli_cmd_flag_none,
"[verbose] = get current WPA/EAPOL/EAP status" },
- { "ping", wpa_cli_cmd_ping,
+ { "ifname", wpa_cli_cmd_ifname, NULL,
+ cli_cmd_flag_none,
+ "= get current interface name" },
+ { "ping", wpa_cli_cmd_ping, NULL,
cli_cmd_flag_none,
"= pings wpa_supplicant" },
- { "relog", wpa_cli_cmd_relog,
+ { "relog", wpa_cli_cmd_relog, NULL,
cli_cmd_flag_none,
"= re-open log-file (allow rolling logs)" },
- { "note", wpa_cli_cmd_note,
+ { "note", wpa_cli_cmd_note, NULL,
cli_cmd_flag_none,
"<text> = add a note to wpa_supplicant debug log" },
- { "mib", wpa_cli_cmd_mib,
+ { "mib", wpa_cli_cmd_mib, NULL,
cli_cmd_flag_none,
"= get MIB variables (dot1x, dot11)" },
- { "help", wpa_cli_cmd_help,
+ { "help", wpa_cli_cmd_help, wpa_cli_complete_help,
cli_cmd_flag_none,
- "= show this usage help" },
- { "interface", wpa_cli_cmd_interface,
+ "[command] = show usage help" },
+ { "interface", wpa_cli_cmd_interface, NULL,
cli_cmd_flag_none,
"[ifname] = show interfaces/select interface" },
- { "level", wpa_cli_cmd_level,
+ { "level", wpa_cli_cmd_level, NULL,
cli_cmd_flag_none,
"<debug level> = change debug level" },
- { "license", wpa_cli_cmd_license,
+ { "license", wpa_cli_cmd_license, NULL,
cli_cmd_flag_none,
"= show full wpa_cli license" },
- { "quit", wpa_cli_cmd_quit,
+ { "quit", wpa_cli_cmd_quit, NULL,
cli_cmd_flag_none,
"= exit wpa_cli" },
- { "set", wpa_cli_cmd_set,
+ { "set", wpa_cli_cmd_set, NULL,
cli_cmd_flag_none,
"= set variables (shows list of variables when run without "
"arguments)" },
- { "get", wpa_cli_cmd_get,
+ { "get", wpa_cli_cmd_get, NULL,
cli_cmd_flag_none,
"<name> = get information" },
- { "logon", wpa_cli_cmd_logon,
+ { "logon", wpa_cli_cmd_logon, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logon" },
- { "logoff", wpa_cli_cmd_logoff,
+ { "logoff", wpa_cli_cmd_logoff, NULL,
cli_cmd_flag_none,
"= IEEE 802.1X EAPOL state machine logoff" },
- { "pmksa", wpa_cli_cmd_pmksa,
+ { "pmksa", wpa_cli_cmd_pmksa, NULL,
cli_cmd_flag_none,
"= show PMKSA cache" },
- { "reassociate", wpa_cli_cmd_reassociate,
+ { "reassociate", wpa_cli_cmd_reassociate, NULL,
cli_cmd_flag_none,
"= force reassociation" },
- { "preauthenticate", wpa_cli_cmd_preauthenticate,
+ { "preauthenticate", wpa_cli_cmd_preauthenticate, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = force preauthentication" },
- { "identity", wpa_cli_cmd_identity,
+ { "identity", wpa_cli_cmd_identity, NULL,
cli_cmd_flag_none,
"<network id> <identity> = configure identity for an SSID" },
- { "password", wpa_cli_cmd_password,
+ { "password", wpa_cli_cmd_password, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = configure password for an SSID" },
- { "new_password", wpa_cli_cmd_new_password,
+ { "new_password", wpa_cli_cmd_new_password, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = change password for an SSID" },
- { "pin", wpa_cli_cmd_pin,
+ { "pin", wpa_cli_cmd_pin, NULL,
cli_cmd_flag_sensitive,
"<network id> <pin> = configure pin for an SSID" },
- { "otp", wpa_cli_cmd_otp,
+ { "otp", wpa_cli_cmd_otp, NULL,
cli_cmd_flag_sensitive,
"<network id> <password> = configure one-time-password for an SSID"
},
- { "passphrase", wpa_cli_cmd_passphrase,
+ { "passphrase", wpa_cli_cmd_passphrase, NULL,
cli_cmd_flag_sensitive,
"<network id> <passphrase> = configure private key passphrase\n"
" for an SSID" },
- { "bssid", wpa_cli_cmd_bssid,
+ { "bssid", wpa_cli_cmd_bssid, NULL,
cli_cmd_flag_none,
"<network id> <BSSID> = set preferred BSSID for an SSID" },
- { "blacklist", wpa_cli_cmd_blacklist,
+ { "blacklist", wpa_cli_cmd_blacklist, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<BSSID> = add a BSSID to the blacklist\n"
"blacklist clear = clear the blacklist\n"
"blacklist = display the blacklist" },
- { "log_level", wpa_cli_cmd_log_level,
+ { "log_level", wpa_cli_cmd_log_level, NULL,
cli_cmd_flag_none,
"<level> [<timestamp>] = update the log level/timestamp\n"
"log_level = display the current log level and log options" },
- { "list_networks", wpa_cli_cmd_list_networks,
+ { "list_networks", wpa_cli_cmd_list_networks, NULL,
cli_cmd_flag_none,
"= list configured networks" },
- { "select_network", wpa_cli_cmd_select_network,
+ { "select_network", wpa_cli_cmd_select_network, NULL,
cli_cmd_flag_none,
"<network id> = select a network (disable others)" },
- { "enable_network", wpa_cli_cmd_enable_network,
+ { "enable_network", wpa_cli_cmd_enable_network, NULL,
cli_cmd_flag_none,
"<network id> = enable a network" },
- { "disable_network", wpa_cli_cmd_disable_network,
+ { "disable_network", wpa_cli_cmd_disable_network, NULL,
cli_cmd_flag_none,
"<network id> = disable a network" },
- { "add_network", wpa_cli_cmd_add_network,
+ { "add_network", wpa_cli_cmd_add_network, NULL,
cli_cmd_flag_none,
"= add a network" },
- { "remove_network", wpa_cli_cmd_remove_network,
+ { "remove_network", wpa_cli_cmd_remove_network, NULL,
cli_cmd_flag_none,
"<network id> = remove a network" },
- { "set_network", wpa_cli_cmd_set_network,
+ { "set_network", wpa_cli_cmd_set_network, NULL,
cli_cmd_flag_sensitive,
"<network id> <variable> <value> = set network variables (shows\n"
" list of variables when run without arguments)" },
- { "get_network", wpa_cli_cmd_get_network,
+ { "get_network", wpa_cli_cmd_get_network, NULL,
cli_cmd_flag_none,
"<network id> <variable> = get network variables" },
- { "list_creds", wpa_cli_cmd_list_creds,
+ { "list_creds", wpa_cli_cmd_list_creds, NULL,
cli_cmd_flag_none,
"= list configured credentials" },
- { "add_cred", wpa_cli_cmd_add_cred,
+ { "add_cred", wpa_cli_cmd_add_cred, NULL,
cli_cmd_flag_none,
"= add a credential" },
- { "remove_cred", wpa_cli_cmd_remove_cred,
+ { "remove_cred", wpa_cli_cmd_remove_cred, NULL,
cli_cmd_flag_none,
"<cred id> = remove a credential" },
- { "set_cred", wpa_cli_cmd_set_cred,
+ { "set_cred", wpa_cli_cmd_set_cred, NULL,
cli_cmd_flag_sensitive,
"<cred id> <variable> <value> = set credential variables" },
- { "save_config", wpa_cli_cmd_save_config,
+ { "save_config", wpa_cli_cmd_save_config, NULL,
cli_cmd_flag_none,
"= save the current configuration" },
- { "disconnect", wpa_cli_cmd_disconnect,
+ { "disconnect", wpa_cli_cmd_disconnect, NULL,
cli_cmd_flag_none,
"= disconnect and wait for reassociate/reconnect command before\n"
" connecting" },
- { "reconnect", wpa_cli_cmd_reconnect,
+ { "reconnect", wpa_cli_cmd_reconnect, NULL,
cli_cmd_flag_none,
"= like reassociate, but only takes effect if already disconnected"
},
- { "scan", wpa_cli_cmd_scan,
+ { "scan", wpa_cli_cmd_scan, NULL,
cli_cmd_flag_none,
"= request new BSS scan" },
- { "scan_results", wpa_cli_cmd_scan_results,
+ { "scan_results", wpa_cli_cmd_scan_results, NULL,
cli_cmd_flag_none,
"= get latest scan results" },
- { "bss", wpa_cli_cmd_bss,
+ { "bss", wpa_cli_cmd_bss, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<<idx> | <bssid>> = get detailed scan result info" },
- { "get_capability", wpa_cli_cmd_get_capability,
+ { "get_capability", wpa_cli_cmd_get_capability, NULL,
cli_cmd_flag_none,
- "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels>\n"
- " = get capabilities" },
- { "reconfigure", wpa_cli_cmd_reconfigure,
+ "<eap/pairwise/group/key_mgmt/proto/auth_alg/channels> "
+ "= get capabilies" },
+ { "reconfigure", wpa_cli_cmd_reconfigure, NULL,
cli_cmd_flag_none,
"= force wpa_supplicant to re-read its configuration file" },
- { "terminate", wpa_cli_cmd_terminate,
+ { "terminate", wpa_cli_cmd_terminate, NULL,
cli_cmd_flag_none,
"= terminate wpa_supplicant" },
- { "interface_add", wpa_cli_cmd_interface_add,
+ { "interface_add", wpa_cli_cmd_interface_add, NULL,
cli_cmd_flag_none,
"<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
" <bridge_name> = adds new interface, all parameters but <ifname>\n"
" are optional" },
- { "interface_remove", wpa_cli_cmd_interface_remove,
+ { "interface_remove", wpa_cli_cmd_interface_remove, NULL,
cli_cmd_flag_none,
"<ifname> = removes the interface" },
- { "interface_list", wpa_cli_cmd_interface_list,
+ { "interface_list", wpa_cli_cmd_interface_list, NULL,
cli_cmd_flag_none,
"= list available interfaces" },
- { "ap_scan", wpa_cli_cmd_ap_scan,
+ { "ap_scan", wpa_cli_cmd_ap_scan, NULL,
cli_cmd_flag_none,
"<value> = set ap_scan parameter" },
- { "scan_interval", wpa_cli_cmd_scan_interval,
+ { "scan_interval", wpa_cli_cmd_scan_interval, NULL,
cli_cmd_flag_none,
"<value> = set scan_interval parameter (in seconds)" },
- { "bss_expire_age", wpa_cli_cmd_bss_expire_age,
+ { "bss_expire_age", wpa_cli_cmd_bss_expire_age, NULL,
cli_cmd_flag_none,
"<value> = set BSS expiration age parameter" },
- { "bss_expire_count", wpa_cli_cmd_bss_expire_count,
+ { "bss_expire_count", wpa_cli_cmd_bss_expire_count, NULL,
cli_cmd_flag_none,
"<value> = set BSS expiration scan count parameter" },
- { "stkstart", wpa_cli_cmd_stkstart,
+ { "bss_flush", wpa_cli_cmd_bss_flush, NULL,
+ cli_cmd_flag_none,
+ "<value> = set BSS flush age (0 by default)" },
+ { "stkstart", wpa_cli_cmd_stkstart, NULL,
cli_cmd_flag_none,
"<addr> = request STK negotiation with <addr>" },
- { "ft_ds", wpa_cli_cmd_ft_ds,
+ { "ft_ds", wpa_cli_cmd_ft_ds, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = request over-the-DS FT with <addr>" },
- { "wps_pbc", wpa_cli_cmd_wps_pbc,
+ { "wps_pbc", wpa_cli_cmd_wps_pbc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
- { "wps_pin", wpa_cli_cmd_wps_pin,
+ { "wps_pin", wpa_cli_cmd_wps_pin, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
"<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
"hardcoded)" },
- { "wps_check_pin", wpa_cli_cmd_wps_check_pin,
+ { "wps_check_pin", wpa_cli_cmd_wps_check_pin, NULL,
cli_cmd_flag_sensitive,
"<PIN> = verify PIN checksum" },
- { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
+ { "wps_cancel", wpa_cli_cmd_wps_cancel, NULL, cli_cmd_flag_none,
"Cancels the pending WPS operation" },
#ifdef CONFIG_WPS_OOB
- { "wps_oob", wpa_cli_cmd_wps_oob,
+ { "wps_oob", wpa_cli_cmd_wps_oob, NULL,
cli_cmd_flag_sensitive,
"<DEV_TYPE> <PATH> <METHOD> [DEV_NAME] = start WPS OOB" },
#endif /* CONFIG_WPS_OOB */
#ifdef CONFIG_WPS_NFC
- { "wps_nfc", wpa_cli_cmd_wps_nfc,
+ { "wps_nfc", wpa_cli_cmd_wps_nfc, wpa_cli_complete_bss,
cli_cmd_flag_none,
"[BSSID] = start Wi-Fi Protected Setup: NFC" },
- { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token,
+ { "wps_nfc_token", wpa_cli_cmd_wps_nfc_token, NULL,
cli_cmd_flag_none,
"<WPS|NDEF> = create password token" },
- { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read,
+ { "wps_nfc_tag_read", wpa_cli_cmd_wps_nfc_tag_read, NULL,
cli_cmd_flag_sensitive,
"<hexdump of payload> = report read NFC tag with WPS data" },
#endif /* CONFIG_WPS_NFC */
- { "wps_reg", wpa_cli_cmd_wps_reg,
+ { "wps_reg", wpa_cli_cmd_wps_reg, wpa_cli_complete_bss,
cli_cmd_flag_sensitive,
"<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
- { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin,
+ { "wps_ap_pin", wpa_cli_cmd_wps_ap_pin, NULL,
cli_cmd_flag_sensitive,
"[params..] = enable/disable AP PIN" },
- { "wps_er_start", wpa_cli_cmd_wps_er_start,
+ { "wps_er_start", wpa_cli_cmd_wps_er_start, NULL,
cli_cmd_flag_none,
"[IP address] = start Wi-Fi Protected Setup External Registrar" },
- { "wps_er_stop", wpa_cli_cmd_wps_er_stop,
+ { "wps_er_stop", wpa_cli_cmd_wps_er_stop, NULL,
cli_cmd_flag_none,
"= stop Wi-Fi Protected Setup External Registrar" },
- { "wps_er_pin", wpa_cli_cmd_wps_er_pin,
+ { "wps_er_pin", wpa_cli_cmd_wps_er_pin, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = add an Enrollee PIN to External Registrar" },
- { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc,
+ { "wps_er_pbc", wpa_cli_cmd_wps_er_pbc, NULL,
cli_cmd_flag_none,
"<UUID> = accept an Enrollee PBC using External Registrar" },
- { "wps_er_learn", wpa_cli_cmd_wps_er_learn,
+ { "wps_er_learn", wpa_cli_cmd_wps_er_learn, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> = learn AP configuration" },
- { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config,
+ { "wps_er_set_config", wpa_cli_cmd_wps_er_set_config, NULL,
cli_cmd_flag_none,
"<UUID> <network id> = set AP configuration for enrolling" },
- { "wps_er_config", wpa_cli_cmd_wps_er_config,
+ { "wps_er_config", wpa_cli_cmd_wps_er_config, NULL,
cli_cmd_flag_sensitive,
"<UUID> <PIN> <SSID> <auth> <encr> <key> = configure AP" },
#ifdef CONFIG_WPS_NFC
- { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token,
+ { "wps_er_nfc_config_token", wpa_cli_cmd_wps_er_nfc_config_token, NULL,
cli_cmd_flag_none,
"<WPS/NDEF> <UUID> = build NFC configuration token" },
#endif /* CONFIG_WPS_NFC */
- { "ibss_rsn", wpa_cli_cmd_ibss_rsn,
+ { "ibss_rsn", wpa_cli_cmd_ibss_rsn, NULL,
cli_cmd_flag_none,
"<addr> = request RSN authentication with <addr> in IBSS" },
#ifdef CONFIG_AP
- { "sta", wpa_cli_cmd_sta,
+ { "sta", wpa_cli_cmd_sta, NULL,
cli_cmd_flag_none,
"<addr> = get information about an associated station (AP)" },
- { "all_sta", wpa_cli_cmd_all_sta,
+ { "all_sta", wpa_cli_cmd_all_sta, NULL,
cli_cmd_flag_none,
"= get information about all associated stations (AP)" },
- { "deauthenticate", wpa_cli_cmd_deauthenticate,
+ { "deauthenticate", wpa_cli_cmd_deauthenticate, NULL,
cli_cmd_flag_none,
"<addr> = deauthenticate a station" },
- { "disassociate", wpa_cli_cmd_disassociate,
+ { "disassociate", wpa_cli_cmd_disassociate, NULL,
cli_cmd_flag_none,
"<addr> = disassociate a station" },
#endif /* CONFIG_AP */
- { "suspend", wpa_cli_cmd_suspend, cli_cmd_flag_none,
+ { "suspend", wpa_cli_cmd_suspend, NULL, cli_cmd_flag_none,
"= notification of suspend/hibernate" },
- { "resume", wpa_cli_cmd_resume, cli_cmd_flag_none,
+ { "resume", wpa_cli_cmd_resume, NULL, cli_cmd_flag_none,
"= notification of resume/thaw" },
- { "drop_sa", wpa_cli_cmd_drop_sa, cli_cmd_flag_none,
+ { "drop_sa", wpa_cli_cmd_drop_sa, NULL, cli_cmd_flag_none,
"= drop SA without deauth/disassoc (test command)" },
- { "roam", wpa_cli_cmd_roam,
+ { "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
cli_cmd_flag_none,
"<addr> = roam to the specified BSS" },
#ifdef CONFIG_P2P
- { "p2p_find", wpa_cli_cmd_p2p_find, cli_cmd_flag_none,
+ { "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
+ cli_cmd_flag_none,
"[timeout] [type=*] = find P2P Devices for up-to timeout seconds" },
- { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, cli_cmd_flag_none,
+ { "p2p_stop_find", wpa_cli_cmd_p2p_stop_find, NULL, cli_cmd_flag_none,
"= stop P2P Devices search" },
- { "p2p_connect", wpa_cli_cmd_p2p_connect, cli_cmd_flag_none,
- "<addr> <\"pbc\"|PIN> = connect to a P2P Devices" },
- { "p2p_listen", wpa_cli_cmd_p2p_listen, cli_cmd_flag_none,
+ { "p2p_connect", wpa_cli_cmd_p2p_connect, wpa_cli_complete_p2p_connect,
+ cli_cmd_flag_none,
+ "<addr> <\"pbc\"|PIN> [ht40] = connect to a P2P Device" },
+ { "p2p_listen", wpa_cli_cmd_p2p_listen, NULL, cli_cmd_flag_none,
"[timeout] = listen for P2P Devices for up-to timeout seconds" },
- { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove, cli_cmd_flag_none,
+ { "p2p_group_remove", wpa_cli_cmd_p2p_group_remove,
+ wpa_cli_complete_p2p_group_remove, cli_cmd_flag_none,
"<ifname> = remove P2P group interface (terminate group if GO)" },
- { "p2p_group_add", wpa_cli_cmd_p2p_group_add, cli_cmd_flag_none,
- "= add a new P2P group (local end as GO)" },
- { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc, cli_cmd_flag_none,
+ { "p2p_group_add", wpa_cli_cmd_p2p_group_add, NULL, cli_cmd_flag_none,
+ "[ht40] = add a new P2P group (local end as GO)" },
+ { "p2p_prov_disc", wpa_cli_cmd_p2p_prov_disc,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <method> = request provisioning discovery" },
- { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase,
+ { "p2p_get_passphrase", wpa_cli_cmd_p2p_get_passphrase, NULL,
cli_cmd_flag_none,
"= get the passphrase for a group (GO only)" },
{ "p2p_serv_disc_req", wpa_cli_cmd_p2p_serv_disc_req,
- cli_cmd_flag_none,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<addr> <TLVs> = schedule service discovery request" },
{ "p2p_serv_disc_cancel_req", wpa_cli_cmd_p2p_serv_disc_cancel_req,
- cli_cmd_flag_none,
+ NULL, cli_cmd_flag_none,
"<id> = cancel pending service discovery request" },
- { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp,
+ { "p2p_serv_disc_resp", wpa_cli_cmd_p2p_serv_disc_resp, NULL,
cli_cmd_flag_none,
"<freq> <addr> <dialog token> <TLVs> = service discovery response" },
- { "p2p_service_update", wpa_cli_cmd_p2p_service_update,
+ { "p2p_service_update", wpa_cli_cmd_p2p_service_update, NULL,
cli_cmd_flag_none,
"= indicate change in local services" },
- { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external,
+ { "p2p_serv_disc_external", wpa_cli_cmd_p2p_serv_disc_external, NULL,
cli_cmd_flag_none,
"<external> = set external processing of service discovery" },
- { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush,
+ { "p2p_service_flush", wpa_cli_cmd_p2p_service_flush, NULL,
cli_cmd_flag_none,
"= remove all stored service entries" },
- { "p2p_service_add", wpa_cli_cmd_p2p_service_add,
+ { "p2p_service_add", wpa_cli_cmd_p2p_service_add, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> <response|service> = add a local "
"service" },
- { "p2p_service_del", wpa_cli_cmd_p2p_service_del,
+ { "p2p_service_del", wpa_cli_cmd_p2p_service_del, NULL,
cli_cmd_flag_none,
"<bonjour|upnp> <query|version> [|service] = remove a local "
"service" },
- { "p2p_reject", wpa_cli_cmd_p2p_reject,
+ { "p2p_reject", wpa_cli_cmd_p2p_reject, wpa_cli_complete_p2p_peer,
cli_cmd_flag_none,
"<addr> = reject connection attempts from a specific peer" },
- { "p2p_invite", wpa_cli_cmd_p2p_invite,
+ { "p2p_invite", wpa_cli_cmd_p2p_invite, NULL,
cli_cmd_flag_none,
"<cmd> [peer=addr] = invite peer" },
- { "p2p_peers", wpa_cli_cmd_p2p_peers, cli_cmd_flag_none,
+ { "p2p_peers", wpa_cli_cmd_p2p_peers, NULL, cli_cmd_flag_none,
"[discovered] = list known (optionally, only fully discovered) P2P "
"peers" },
- { "p2p_peer", wpa_cli_cmd_p2p_peer, cli_cmd_flag_none,
+ { "p2p_peer", wpa_cli_cmd_p2p_peer, wpa_cli_complete_p2p_peer,
+ cli_cmd_flag_none,
"<address> = show information about known P2P peer" },
- { "p2p_set", wpa_cli_cmd_p2p_set, cli_cmd_flag_none,
+ { "p2p_set", wpa_cli_cmd_p2p_set, NULL, cli_cmd_flag_none,
"<field> <value> = set a P2P parameter" },
- { "p2p_flush", wpa_cli_cmd_p2p_flush, cli_cmd_flag_none,
+ { "p2p_flush", wpa_cli_cmd_p2p_flush, NULL, cli_cmd_flag_none,
"= flush P2P state" },
- { "p2p_cancel", wpa_cli_cmd_p2p_cancel, cli_cmd_flag_none,
+ { "p2p_cancel", wpa_cli_cmd_p2p_cancel, NULL, cli_cmd_flag_none,
"= cancel P2P group formation" },
- { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize, cli_cmd_flag_none,
+ { "p2p_unauthorize", wpa_cli_cmd_p2p_unauthorize,
+ wpa_cli_complete_p2p_peer, cli_cmd_flag_none,
"<address> = unauthorize a peer" },
- { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, cli_cmd_flag_none,
+ { "p2p_presence_req", wpa_cli_cmd_p2p_presence_req, NULL,
+ cli_cmd_flag_none,
"[<duration> <interval>] [<duration> <interval>] = request GO "
"presence" },
- { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
+ { "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, NULL,
+ cli_cmd_flag_none,
"[<period> <interval>] = set extended listen timing" },
#endif /* CONFIG_P2P */
-
+#ifdef CONFIG_WIFI_DISPLAY
+ { "wfd_subelem_set", wpa_cli_cmd_wfd_subelem_set, NULL,
+ cli_cmd_flag_none,
+ "<subelem> [contents] = set Wi-Fi Display subelement" },
+ { "wfd_subelem_get", wpa_cli_cmd_wfd_subelem_get, NULL,
+ cli_cmd_flag_none,
+ "<subelem> = get Wi-Fi Display subelement" },
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_INTERWORKING
- { "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
+ { "fetch_anqp", wpa_cli_cmd_fetch_anqp, NULL, cli_cmd_flag_none,
"= fetch ANQP information for all APs" },
- { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
+ { "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, NULL,
+ cli_cmd_flag_none,
"= stop fetch_anqp operation" },
- { "interworking_select", wpa_cli_cmd_interworking_select,
+ { "interworking_select", wpa_cli_cmd_interworking_select, NULL,
cli_cmd_flag_none,
"[auto] = perform Interworking network selection" },
{ "interworking_connect", wpa_cli_cmd_interworking_connect,
- cli_cmd_flag_none,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
"<BSSID> = connect using Interworking credentials" },
- { "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+ { "anqp_get", wpa_cli_cmd_anqp_get, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
"<addr> <info id>[,<info id>]... = request ANQP information" },
+ { "gas_request", wpa_cli_cmd_gas_request, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
+ "<addr> <AdvProtoID> [QueryReq] = GAS request" },
+ { "gas_response_get", wpa_cli_cmd_gas_response_get,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
+ "<addr> <dialog token> [start,len] = Fetch last GAS response" },
#endif /* CONFIG_INTERWORKING */
#ifdef CONFIG_HS20
- { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, cli_cmd_flag_none,
+ { "hs20_anqp_get", wpa_cli_cmd_hs20_anqp_get, wpa_cli_complete_bss,
+ cli_cmd_flag_none,
"<addr> <subtype>[,<subtype>]... = request HS 2.0 ANQP information"
},
{ "nai_home_realm_list", wpa_cli_cmd_get_nai_home_realm_list,
- cli_cmd_flag_none,
+ wpa_cli_complete_bss, cli_cmd_flag_none,
"<addr> <home realm> = get HS20 nai home realm list" },
#endif /* CONFIG_HS20 */
- { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
+ { "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, NULL,
+ cli_cmd_flag_none,
"<0/1> = disable/enable automatic reconnection" },
- { "tdls_discover", wpa_cli_cmd_tdls_discover,
+ { "tdls_discover", wpa_cli_cmd_tdls_discover, NULL,
cli_cmd_flag_none,
"<addr> = request TDLS discovery with <addr>" },
- { "tdls_setup", wpa_cli_cmd_tdls_setup,
+ { "tdls_setup", wpa_cli_cmd_tdls_setup, NULL,
cli_cmd_flag_none,
"<addr> = request TDLS setup with <addr>" },
- { "tdls_teardown", wpa_cli_cmd_tdls_teardown,
+ { "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
cli_cmd_flag_none,
"<addr> = tear down TDLS with <addr>" },
- { "signal_poll", wpa_cli_cmd_signal_poll,
+ { "signal_poll", wpa_cli_cmd_signal_poll, NULL,
cli_cmd_flag_none,
"= get signal parameters" },
- { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll,
+ { "pktcnt_poll", wpa_cli_cmd_pktcnt_poll, NULL,
cli_cmd_flag_none,
"= get TX/RX packet counters" },
- { "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+ { "reauthenticate", wpa_cli_cmd_reauthenticate, NULL,
+ cli_cmd_flag_none,
"= trigger IEEE 802.1X/EAPOL reauthentication" },
#ifdef CONFIG_AUTOSCAN
- { "autoscan", wpa_cli_cmd_autoscan, cli_cmd_flag_none,
+ { "autoscan", wpa_cli_cmd_autoscan, NULL, cli_cmd_flag_none,
"[params] = Set or unset (if none) autoscan parameters" },
#endif /* CONFIG_AUTOSCAN */
+ { "raw", wpa_cli_cmd_raw, NULL, cli_cmd_flag_sensitive,
+ "<params..> = Sent unprocessed command" },
#ifdef ANDROID
- { "driver", wpa_cli_cmd_driver,
+ { "driver", wpa_cli_cmd_driver, NULL,
cli_cmd_flag_none,
"<command> = driver private commands" },
#endif
- { NULL, NULL, cli_cmd_flag_none, NULL }
+ { NULL, NULL, NULL, cli_cmd_flag_none, NULL }
};
@@ -3413,12 +2713,14 @@
}
-static void print_help(void)
+static void print_help(const char *cmd)
{
int n;
printf("commands:\n");
- for (n = 0; wpa_cli_commands[n].cmd; n++)
- print_cmd_help(&wpa_cli_commands[n], " ");
+ for (n = 0; wpa_cli_commands[n].cmd; n++) {
+ if (cmd == NULL || str_starts(wpa_cli_commands[n].cmd, cmd))
+ print_cmd_help(&wpa_cli_commands[n], " ");
+ }
}
@@ -3449,7 +2751,7 @@
int i, count;
count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
- res = os_zalloc(count * sizeof(char *));
+ res = os_calloc(count, sizeof(char *));
if (res == NULL)
return NULL;
@@ -3468,19 +2770,11 @@
{
int i;
- if (os_strcasecmp(cmd, "bss") == 0)
- return wpa_cli_complete_bss(str, pos);
-#ifdef CONFIG_P2P
- if (os_strcasecmp(cmd, "p2p_connect") == 0)
- return wpa_cli_complete_p2p_connect(str, pos);
- if (os_strcasecmp(cmd, "p2p_peer") == 0)
- return wpa_cli_complete_p2p_peer(str, pos);
- if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
- return wpa_cli_complete_p2p_group_remove(str, pos);
-#endif /* CONFIG_P2P */
-
for (i = 0; wpa_cli_commands[i].cmd; i++) {
if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
+ if (wpa_cli_commands[i].completion)
+ return wpa_cli_commands[i].completion(str,
+ pos);
edit_clear_line();
printf("\r%s\n", wpa_cli_commands[i].usage);
edit_redraw();
@@ -3691,7 +2985,14 @@
static void wpa_cli_reconnect(void)
{
wpa_cli_close_connection();
- wpa_cli_open_connection(ctrl_ifname, 1);
+ if (wpa_cli_open_connection(ctrl_ifname, 1) < 0)
+ return;
+
+ if (interactive) {
+ edit_clear_line();
+ printf("\rConnection to wpa_supplicant re-established\n");
+ edit_redraw();
+ }
}
@@ -3763,6 +3064,33 @@
}
+static int check_terminating(const char *msg)
+{
+ const char *pos = msg;
+
+ if (*pos == '<') {
+ /* skip priority */
+ pos = os_strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ if (str_match(pos, WPA_EVENT_TERMINATING) && ctrl_conn) {
+ edit_clear_line();
+ printf("\rConnection to wpa_supplicant lost - trying to "
+ "reconnect\n");
+ edit_redraw();
+ wpa_cli_attached = 0;
+ wpa_cli_close_connection();
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
{
if (ctrl_conn == NULL) {
@@ -3783,6 +3111,9 @@
printf("\r%s\n", buf);
edit_redraw();
}
+
+ if (interactive && check_terminating(buf) > 0)
+ return;
}
} else {
printf("Could not read pending message.\n");
@@ -3842,12 +3173,6 @@
}
-static void wpa_cli_eloop_terminate(int sig, void *signal_ctx)
-{
- eloop_terminate();
-}
-
-
static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
wpa_cli_recv_pending(mon_conn, 0);
@@ -3870,11 +3195,18 @@
}
-static void wpa_cli_interactive(void)
-{
- char *home, *hfile = NULL;
+static int warning_displayed = 0;
+static char *hfile = NULL;
+static int edit_started = 0;
- printf("\nInteractive mode\n\n");
+static void start_edit(void)
+{
+ char *home;
+ char *ps = NULL;
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+ ps = wpa_ctrl_get_remote_ifname(ctrl_conn);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
home = getenv("HOME");
if (home) {
@@ -3885,17 +3217,52 @@
os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
}
- eloop_register_signal_terminate(wpa_cli_eloop_terminate, NULL);
- edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
- wpa_cli_edit_completion_cb, NULL, hfile);
- eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+ if (edit_init(wpa_cli_edit_cmd_cb, wpa_cli_edit_eof_cb,
+ wpa_cli_edit_completion_cb, NULL, hfile, ps) < 0) {
+ eloop_terminate();
+ return;
+ }
+ edit_started = 1;
+ eloop_register_timeout(ping_interval, 0, wpa_cli_ping, NULL, NULL);
+}
+
+
+static void try_connection(void *eloop_ctx, void *timeout_ctx)
+{
+ if (ctrl_ifname == NULL)
+ ctrl_ifname = wpa_cli_get_default_ifname();
+
+ if (!wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
+ if (!warning_displayed) {
+ printf("Could not connect to wpa_supplicant: "
+ "%s - re-trying\n", ctrl_ifname);
+ warning_displayed = 1;
+ }
+ eloop_register_timeout(1, 0, try_connection, NULL, NULL);
+ return;
+ }
+
+ if (warning_displayed)
+ printf("Connection established.\n");
+
+ start_edit();
+}
+
+
+static void wpa_cli_interactive(void)
+{
+ printf("\nInteractive mode\n\n");
+
+ eloop_register_timeout(0, 0, try_connection, NULL, NULL);
eloop_run();
+ eloop_cancel_timeout(try_connection, NULL, NULL);
cli_txt_list_flush(&p2p_peers);
cli_txt_list_flush(&p2p_groups);
cli_txt_list_flush(&bsses);
- edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
+ if (edit_started)
+ edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
os_free(hfile);
eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
wpa_cli_close_connection();
@@ -3954,10 +3321,10 @@
os_program_deinit();
}
-static void wpa_cli_terminate(int sig)
+
+static void wpa_cli_terminate(int sig, void *ctx)
{
- wpa_cli_cleanup();
- exit(0);
+ eloop_terminate();
}
@@ -4031,7 +3398,6 @@
int main(int argc, char *argv[])
{
- int warning_displayed = 0;
int c;
int daemonize = 0;
int ret = 0;
@@ -4101,30 +3467,13 @@
}
}
-#ifndef _WIN32_WCE
- signal(SIGINT, wpa_cli_terminate);
- signal(SIGTERM, wpa_cli_terminate);
-#endif /* _WIN32_WCE */
+ eloop_register_signal_terminate(wpa_cli_terminate, NULL);
if (ctrl_ifname == NULL)
ctrl_ifname = wpa_cli_get_default_ifname();
if (interactive) {
- for (; !global;) {
- if (wpa_cli_open_connection(ctrl_ifname, 1) == 0) {
- if (warning_displayed)
- printf("Connection established.\n");
- break;
- }
-
- if (!warning_displayed) {
- printf("Could not connect to wpa_supplicant: "
- "%s - re-trying\n", ctrl_ifname);
- warning_displayed = 1;
- }
- os_sleep(1, 0);
- continue;
- }
+ wpa_cli_interactive();
} else {
if (!global &&
wpa_cli_open_connection(ctrl_ifname, 0) < 0) {
@@ -4143,18 +3492,17 @@
return -1;
}
}
+
+ if (daemonize && os_daemonize(pid_file))
+ return -1;
+
+ if (action_file)
+ wpa_cli_action(ctrl_conn);
+ else
+ ret = wpa_request(ctrl_conn, argc - optind,
+ &argv[optind]);
}
- if (daemonize && os_daemonize(pid_file))
- return -1;
-
- if (interactive)
- wpa_cli_interactive();
- else if (action_file)
- wpa_cli_action(ctrl_conn);
- else
- ret = wpa_request(ctrl_conn, argc - optind, &argv[optind]);
-
os_free(ctrl_ifname);
eloop_destroy();
wpa_cli_cleanup();
diff --git a/wpa_supplicant/wpa_passphrase.c b/wpa_supplicant/wpa_passphrase.c
index a9ec236..9b568f0 100644
--- a/wpa_supplicant/wpa_passphrase.c
+++ b/wpa_supplicant/wpa_passphrase.c
@@ -52,7 +52,7 @@
return 1;
}
- pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32);
+ pbkdf2_sha1(passphrase, (u8 *) ssid, os_strlen(ssid), 4096, psk, 32);
printf("network={\n");
printf("\tssid=\"%s\"\n", ssid);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 47abd9a..284a91d 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -21,6 +21,7 @@
#include "rsn_supp/wpa.h"
#include "eloop.h"
#include "config.h"
+#include "utils/ext_password.h"
#include "l2_packet/l2_packet.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
@@ -40,6 +41,7 @@
#include "gas_query.h"
#include "ap.h"
#include "p2p_supplicant.h"
+#include "wifi_display.h"
#include "notify.h"
#include "bgscan.h"
#include "autoscan.h"
@@ -153,6 +155,11 @@
keylen = 16;
alg = WPA_ALG_CCMP;
break;
+ case WPA_CIPHER_GCMP:
+ os_memcpy(key, ssid->psk, 16);
+ keylen = 16;
+ alg = WPA_ALG_GCMP;
+ break;
case WPA_CIPHER_TKIP:
/* WPA-None uses the same Michael MIC key for both TX and RX */
os_memcpy(key, ssid->psk, 16 + 8);
@@ -191,6 +198,17 @@
* So, wait a second until scanning again.
*/
wpa_supplicant_req_scan(wpa_s, 1, 0);
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after timed out authentication");
+ }
+ }
+#endif /* CONFIG_P2P */
}
@@ -453,6 +471,11 @@
wpa_s->bssid_filter = NULL;
wnm_bss_keep_alive_deinit(wpa_s);
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+
+ wpabuf_free(wpa_s->last_gas_resp);
}
@@ -554,8 +577,16 @@
* optimization, so the initial connection is not
* affected.
*/
- } else
+ } else {
+ struct wpa_scan_results *scan_res;
wpa_s->bgscan_ssid = wpa_s->current_ssid;
+ scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
+ 0);
+ if (scan_res) {
+ bgscan_notify_scan(wpa_s, scan_res);
+ wpa_scan_results_free(scan_res);
+ }
+ }
} else
wpa_s->bgscan_ssid = NULL;
}
@@ -631,6 +662,7 @@
ssid ? ssid->id : -1,
ssid && ssid->id_str ? ssid->id_str : "");
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
wpa_s->new_connection = 0;
wpa_s->reassociated_connection = 1;
wpa_drv_set_operstate(wpa_s, 1);
@@ -823,6 +855,8 @@
return CIPHER_WEP104;
case WPA_CIPHER_CCMP:
return CIPHER_CCMP;
+ case WPA_CIPHER_GCMP:
+ return CIPHER_GCMP;
case WPA_CIPHER_TKIP:
default:
return CIPHER_TKIP;
@@ -999,6 +1033,9 @@
if (sel & WPA_CIPHER_CCMP) {
wpa_s->group_cipher = WPA_CIPHER_CCMP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
+ } else if (sel & WPA_CIPHER_GCMP) {
+ wpa_s->group_cipher = WPA_CIPHER_GCMP;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
} else if (sel & WPA_CIPHER_TKIP) {
wpa_s->group_cipher = WPA_CIPHER_TKIP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
@@ -1018,6 +1055,9 @@
if (sel & WPA_CIPHER_CCMP) {
wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
+ } else if (sel & WPA_CIPHER_GCMP) {
+ wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
+ wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
} else if (sel & WPA_CIPHER_TKIP) {
wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
@@ -1099,13 +1139,70 @@
if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
ssid->passphrase) {
u8 psk[PMK_LEN];
- pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
- bss->ssid_len, 4096, psk, PMK_LEN);
+ pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN);
wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
psk, PMK_LEN);
wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
}
#endif /* CONFIG_NO_PBKDF2 */
+#ifdef CONFIG_EXT_PASSWORD
+ if (ssid->ext_psk) {
+ struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+ ssid->ext_psk);
+ char pw_str[64 + 1];
+ u8 psk[PMK_LEN];
+
+ if (pw == NULL) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
+ "found from external storage");
+ return -1;
+ }
+
+ if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
+ "PSK length %d in external storage",
+ (int) wpabuf_len(pw));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+ pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+ if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+ {
+ pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+ 4096, psk, PMK_LEN);
+ os_memset(pw_str, 0, sizeof(pw_str));
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
+ "external passphrase)",
+ psk, PMK_LEN);
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ } else
+#endif /* CONFIG_NO_PBKDF2 */
+ if (wpabuf_len(pw) == 2 * PMK_LEN) {
+ if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
+ "Invalid PSK hex string");
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+ wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+ } else {
+ wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
+ "PSK available");
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ return -1;
+ }
+
+ os_memset(pw_str, 0, sizeof(pw_str));
+ ext_password_free(pw);
+ }
+#endif /* CONFIG_EXT_PASSWORD */
} else
wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -1257,6 +1354,16 @@
"key management and encryption suites");
return;
}
+ } else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
+ wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+ /*
+ * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+ * use non-WPA since the scan results did not indicate that the
+ * AP is using WPA or WPA2.
+ */
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ wpa_ie_len = 0;
+ wpa_s->wpa_proto = 0;
} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -1570,10 +1677,8 @@
struct wpa_ssid *old_ssid;
wpa_clear_keys(wpa_s, addr);
- wpa_supplicant_mark_disassoc(wpa_s);
old_ssid = wpa_s->current_ssid;
- wpa_s->current_ssid = NULL;
- wpa_s->current_bss = NULL;
+ wpa_supplicant_mark_disassoc(wpa_s);
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
if (old_ssid != wpa_s->current_ssid)
@@ -1662,6 +1767,8 @@
was_disabled = other_ssid->disabled;
other_ssid->disabled = 0;
+ if (was_disabled)
+ wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(
@@ -1682,6 +1789,7 @@
was_disabled = ssid->disabled;
ssid->disabled = 0;
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
if (was_disabled != ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, ssid);
@@ -1752,6 +1860,9 @@
disconnected = 1;
}
+ if (ssid)
+ wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
/*
* Mark all other networks disabled or mark all networks enabled if no
* network specified.
@@ -1763,6 +1874,8 @@
continue; /* do not change persistent P2P group data */
other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+ if (was_disabled && !other_ssid->disabled)
+ wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
if (was_disabled != other_ssid->disabled)
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
@@ -2529,6 +2642,38 @@
}
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+ char *val, *pos;
+
+ ext_password_deinit(wpa_s->ext_pw);
+ wpa_s->ext_pw = NULL;
+ eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+ if (!wpa_s->conf->ext_password_backend)
+ return 0;
+
+ val = os_strdup(wpa_s->conf->ext_password_backend);
+ if (val == NULL)
+ return -1;
+ pos = os_strchr(val, ':');
+ if (pos)
+ *pos++ = '\0';
+
+ wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+ wpa_s->ext_pw = ext_password_init(val, pos);
+ os_free(val);
+ if (wpa_s->ext_pw == NULL) {
+ wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+ return -1;
+ }
+ eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+ return 0;
+}
+
+
static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
@@ -2754,6 +2899,9 @@
if (pcsc_reader_init(wpa_s) < 0)
return -1;
+ if (wpas_init_ext_pw(wpa_s) < 0)
+ return -1;
+
return 0;
}
@@ -3072,6 +3220,14 @@
return NULL;
}
+#ifdef CONFIG_WIFI_DISPLAY
+ if (wifi_display_init(global) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+#endif /* CONFIG_WIFI_DISPLAY */
+
return global;
}
@@ -3123,6 +3279,9 @@
if (global == NULL)
return;
+#ifdef CONFIG_WIFI_DISPLAY
+ wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
#ifdef CONFIG_P2P
wpas_p2p_deinit_global(global);
#endif /* CONFIG_P2P */
@@ -3182,6 +3341,9 @@
}
}
+ if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+ wpas_init_ext_pw(wpa_s);
+
#ifdef CONFIG_WPS
wpas_wps_update_config(wpa_s);
#endif /* CONFIG_WPS */
@@ -3304,6 +3466,17 @@
*/
wpa_supplicant_req_scan(wpa_s, timeout / 1000,
1000 * (timeout % 1000));
+
+#ifdef CONFIG_P2P
+ if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+ wpa_s->global->p2p != NULL) {
+ wpa_s->p2p_cb_on_scan_complete = 0;
+ if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+ wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+ "continued after failed association");
+ }
+ }
+#endif /* CONFIG_P2P */
}
@@ -3417,6 +3590,10 @@
return 1; /* invalid WEP key */
}
+ if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+ !ssid->ext_psk)
+ return 1;
+
return 0;
}
@@ -3429,3 +3606,63 @@
return 0;
return -1;
}
+
+
+void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int dur;
+ struct os_time now;
+
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "Authentication failure but no known "
+ "SSID block");
+ return;
+ }
+
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ return;
+
+ ssid->auth_failures++;
+ if (ssid->auth_failures > 50)
+ dur = 300;
+ else if (ssid->auth_failures > 20)
+ dur = 120;
+ else if (ssid->auth_failures > 10)
+ dur = 60;
+ else if (ssid->auth_failures > 5)
+ dur = 30;
+ else if (ssid->auth_failures > 1)
+ dur = 20;
+ else
+ dur = 10;
+
+ os_get_time(&now);
+ if (now.sec + dur <= ssid->disabled_until.sec)
+ return;
+
+ ssid->disabled_until.sec = now.sec + dur;
+
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
+ "id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+ ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+ ssid->auth_failures, dur);
+}
+
+
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int clear_failures)
+{
+ if (ssid == NULL)
+ return;
+
+ if (ssid->disabled_until.sec) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
+ "id=%d ssid=\"%s\"",
+ ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ }
+ ssid->disabled_until.sec = 0;
+ ssid->disabled_until.usec = 0;
+ if (clear_failures)
+ ssid->auth_failures = 0;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3ebbcc2..0b0ea88 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -241,20 +241,30 @@
# This is an optional set of parameters for automatic scanning
# within an interface in following format:
#autoscan=<autoscan module name>:<module parameters>
-# autoscan is like bgscan but on disconnected or inactive state.
-# For instance, on exponential module parameters would be <base>:<limit>
+# autoscan is like bgscan but on disconnected or inactive state.
+# For instance, on exponential module parameters would be <base>:<limit>
#autoscan=exponential:3:300
# Which means a delay between scans on a base exponential of 3,
-# up to the limit of 300 seconds (3, 9, 27 ... 300)
-# For periodic module, parameters would be <fixed interval>
+# up to the limit of 300 seconds (3, 9, 27 ... 300)
+# For periodic module, parameters would be <fixed interval>
#autoscan=periodic:30
-# So a delay of 30 seconds will be applied between each scan
+# So a delay of 30 seconds will be applied between each scan
# filter_ssids - SSID-based scan result filtering
# 0 = do not filter scan results (default)
# 1 = only include configured SSIDs in scan results/BSS table
#filter_ssids=0
+# Password (and passphrase, etc.) backend for external storage
+# format: <backend name>[:<optional backend parameters>]
+#ext_password_backend=test:pw1=password|pw2=testing
+
+# Timeout in seconds to detect STA inactivity (default: 300 seconds)
+#
+# This timeout value is used in P2P GO mode to clean up
+# inactive stations.
+#p2p_go_max_inactivity=300
+
# Interworking (IEEE 802.11u)
@@ -267,6 +277,14 @@
# is enabled.
# hessid=00:11:22:33:44:55
+# Automatic network selection behavior
+# 0 = do not automatically go through Interworking network selection
+# (i.e., require explicit interworking_select command for this; default)
+# 1 = perform Interworking network selection if one or more
+# credentials have been configured and scan did not find a
+# matching network block
+#auto_interworking=0
+
# credential block
#
# Each credential used for automatic network selection is configured as a set
@@ -336,6 +354,26 @@
# This is used to compare against the Domain Name List to figure out
# whether the AP is operated by the Home SP.
#
+# roaming_consortium: Roaming Consortium OI
+# If roaming_consortium_len is non-zero, this field contains the
+# Roaming Consortium OI that can be used to determine which access
+# points support authentication with this credential. This is an
+# alternative to the use of the realm parameter. When using Roaming
+# Consortium to match the network, the EAP parameters need to be
+# pre-configured with the credential since the NAI Realm information
+# may not be available or fetched.
+#
+# eap: Pre-configured EAP method
+# This optional field can be used to specify which EAP method will be
+# used with this credential. If not set, the EAP method is selected
+# automatically based on ANQP information (e.g., NAI Realm).
+#
+# phase1: Pre-configure Phase 1 (outer authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
+# phase2: Pre-configure Phase 2 (inner authentication) parameters
+# This optional field is used with like the 'eap' parameter.
+#
# for example:
#
#cred={
@@ -350,6 +388,17 @@
# imsi="310026-000000000"
# milenage="90dca4eda45b53cf0f12d7c9c3bc6a89:cb9cccc4b9258e6dca4760379fb82"
#}
+#
+#cred={
+# realm="example.com"
+# username="user"
+# password="password"
+# ca_cert="/etc/wpa_supplicant/ca.pem"
+# domain="example.com"
+# roaming_consortium=223344
+# eap=TTLS
+# phase2="auth=MSCHAPV2"
+#}
# Hotspot 2.0
# hs20=1
@@ -371,8 +420,10 @@
# to external action script through wpa_cli as WPA_ID_STR environment
# variable to make it easier to do network specific configuration.
#
-# ssid: SSID (mandatory); either as an ASCII string with double quotation or
-# as hex string; network name
+# ssid: SSID (mandatory); network name in one of the optional formats:
+# - an ASCII string with double quotation
+# - a hex string (two characters per octet of SSID)
+# - a printf-escaped ASCII string P"<escaped string>"
#
# scan_ssid:
# 0 = do not scan this SSID with specific Probe Request frames (default)
@@ -473,7 +524,8 @@
# The key used in WPA-PSK mode can be entered either as 64 hex-digits, i.e.,
# 32 bytes or as an ASCII passphrase (in which case, the real PSK will be
# generated using the passphrase and SSID). ASCII passphrase must be between
-# 8 and 63 characters (inclusive).
+# 8 and 63 characters (inclusive). ext:<name of external PSK field> format can
+# be used to indicate that the PSK/passphrase is stored in external storage.
# This field is not needed, if WPA-EAP is used.
# Note: Separate tool, wpa_passphrase, can be used to generate 256-bit keys
# from ASCII passphrase. This process uses lot of CPU and wpa_supplicant
@@ -534,7 +586,8 @@
# EAP-PSK/PAX/SAKE/GPSK.
# anonymous_identity: Anonymous identity string for EAP (to be used as the
# unencrypted identity with EAP types that support different tunnelled
-# identity, e.g., EAP-TTLS)
+# identity, e.g., EAP-TTLS). This field can also be used with
+# EAP-SIM/AKA/AKA' to store the pseudonym identity.
# password: Password string for EAP. This field can include either the
# plaintext password (using ASCII or hex string) or a NtPasswordHash
# (16-byte MD4 hash of password) in hash:<32 hex digits> format.
@@ -542,7 +595,8 @@
# MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
# EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
# PSK) is also configured using this field. For EAP-GPSK, this is a
-# variable length PSK.
+# variable length PSK. ext:<name of external password field> format can
+# be used to indicate that the password is stored in external storage.
# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
# or more trusted CA certificates. If ca_cert and ca_path are not
# included, server certificate will not be verified. This is insecure and
@@ -645,6 +699,25 @@
# phase2: Phase2 (inner authentication with TLS tunnel) parameters
# (string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
# "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)
+#
+# TLS-based methods can use the following parameters to control TLS behavior
+# (these are normally in the phase1 parameter, but can be used also in the
+# phase2 parameter when EAP-TLS is used within the inner tunnel):
+# tls_allow_md5=1 - allow MD5-based certificate signatures (depending on the
+# TLS library, these may be disabled by default to enforce stronger
+# security)
+# tls_disable_time_checks=1 - ignore certificate validity time (this requests
+# the TLS library to accept certificates even if they are not currently
+# valid, i.e., have expired or have not yet become valid; this should be
+# used only for testing purposes)
+# tls_disable_session_ticket=1 - disable TLS Session Ticket extension
+# tls_disable_session_ticket=0 - allow TLS Session Ticket extension to be used
+# Note: If not set, this is automatically set to 1 for EAP-TLS/PEAP/TTLS
+# as a workaround for broken authentication server implementations unless
+# EAP workarounds are disabled with eap_workarounds=0.
+# For EAP-FAST, this must be set to 0 (or left unconfigured for the
+# default value to be used automatically).
+#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
# ca_cert2: File path to CA certificate file. This file can have one or more
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3f6669d..6011439 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -239,6 +239,12 @@
WPA_CONC_PREF_STA,
WPA_CONC_PREF_P2P
} conc_pref;
+
+#ifdef CONFIG_WIFI_DISPLAY
+ int wifi_display;
+#define MAX_WFD_SUBELEMS 10
+ struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
+#endif /* CONFIG_WIFI_DISPLAY */
};
@@ -249,6 +255,17 @@
OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
};
+struct wps_ap_info {
+ u8 bssid[ETH_ALEN];
+ enum wps_ap_info_type {
+ WPS_AP_NOT_SEL_REG,
+ WPS_AP_SEL_REG,
+ WPS_AP_SEL_REG_OUR
+ } type;
+ unsigned int tries;
+ struct os_time last_attempt;
+};
+
/**
* struct wpa_supplicant - Internal data for wpa_supplicant interface
*
@@ -514,23 +531,15 @@
*/
char cross_connect_uplink[100];
- enum {
- P2P_GROUP_REMOVAL_UNKNOWN,
- P2P_GROUP_REMOVAL_REQUESTED,
- P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
- P2P_GROUP_REMOVAL_UNAVAILABLE,
- P2P_GROUP_REMOVAL_GO_ENDING_SESSION,
-#ifdef ANDROID_P2P
- P2P_GROUP_REMOVAL_FREQ_CONFLICT
-#endif
- } removal_reason;
-
unsigned int p2p_cb_on_scan_complete:1;
+ unsigned int sta_scan_pending:1;
unsigned int p2p_auto_join:1;
unsigned int p2p_auto_pd:1;
unsigned int p2p_persistent_group:1;
unsigned int p2p_fallback_to_go_neg:1;
unsigned int p2p_pd_before_go_neg:1;
+ unsigned int p2p_go_ht40:1;
+ int p2p_persistent_go_freq;
int p2p_persistent_id;
int p2p_go_intent;
int p2p_connect_freq;
@@ -547,6 +556,10 @@
struct wpa_ssid *connect_without_scan;
+ struct wps_ap_info *wps_ap;
+ size_t num_wps_ap;
+ int wps_ap_iter;
+
int after_wps;
int known_wps_freq;
unsigned int wps_freq;
@@ -564,6 +577,8 @@
unsigned int fetch_anqp_in_progress:1;
unsigned int network_select:1;
unsigned int auto_select:1;
+ unsigned int auto_network_select:1;
+ unsigned int fetch_all_anqp:1;
#endif /* CONFIG_INTERWORKING */
unsigned int drv_capa_known;
@@ -577,6 +592,12 @@
/* WLAN_REASON_* reason codes. Negative if locally generated. */
int disconnect_reason;
+
+ struct ext_password_data *ext_pw;
+
+ struct wpabuf *last_gas_resp;
+ u8 last_gas_addr[ETH_ALEN];
+ u8 last_gas_dialog_token;
};
@@ -659,6 +680,9 @@
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s);
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid, int clear_failures);
void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
/**
@@ -700,4 +724,6 @@
int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index fb4fa22..6aa5205 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -729,6 +729,44 @@
wpas_notify_eap_status(wpa_s, status, parameter);
}
+
+
+static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ char *str;
+ int res;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+ id, len);
+
+ if (wpa_s->current_ssid == NULL)
+ return;
+
+ if (id == NULL) {
+ if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ "NULL", 0) < 0)
+ return;
+ } else {
+ str = os_malloc(len * 2 + 1);
+ if (str == NULL)
+ return;
+ wpa_snprintf_hex(str, len * 2 + 1, id, len);
+ res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+ str, 0);
+ os_free(str);
+ if (res < 0)
+ return;
+ }
+
+ if (wpa_s->conf->update_config) {
+ res = wpa_config_write(wpa_s->confname, wpa_s->conf);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to update config after "
+ "anonymous_id update");
+ }
+ }
+}
#endif /* IEEE8021X_EAPOL */
@@ -761,6 +799,7 @@
ctx->cb = wpa_supplicant_eapol_cb;
ctx->cert_cb = wpa_supplicant_cert_cb;
ctx->status_cb = wpa_supplicant_status_cb;
+ ctx->set_anon_id = wpa_supplicant_set_anon_id;
ctx->cb_ctx = wpa_s;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 0873b1a..23966b8 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -43,6 +43,15 @@
static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
+static void wpas_wps_clear_ap_info(struct wpa_supplicant *wpa_s)
+{
+ os_free(wpa_s->wps_ap);
+ wpa_s->wps_ap = NULL;
+ wpa_s->num_wps_ap = 0;
+ wpa_s->wps_ap_iter = 0;
+}
+
+
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
if (!wpa_s->wps_success &&
@@ -66,6 +75,7 @@
return 1;
}
+ wpas_wps_clear_ap_info(wpa_s);
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && !wpa_s->wps_success)
wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL);
@@ -263,9 +273,13 @@
ssid->eap.phase1 = NULL;
os_free(ssid->eap.eap_methods);
ssid->eap.eap_methods = NULL;
- if (!ssid->p2p_group)
+ if (!ssid->p2p_group) {
ssid->temporary = 0;
- ssid->bssid_set = 0;
+ ssid->bssid_set = 0;
+ }
+ ssid->disabled_until.sec = 0;
+ ssid->disabled_until.usec = 0;
+ ssid->auth_failures = 0;
} else {
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
"received credential");
@@ -353,16 +367,6 @@
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
ssid->proto = WPA_PROTO_WPA;
break;
- case WPS_AUTH_WPA:
- ssid->auth_alg = WPA_AUTH_ALG_OPEN;
- ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- ssid->proto = WPA_PROTO_WPA;
- break;
- case WPS_AUTH_WPA2:
- ssid->auth_alg = WPA_AUTH_ALG_OPEN;
- ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
- ssid->proto = WPA_PROTO_RSN;
- break;
case WPS_AUTH_WPA2PSK:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -712,6 +716,8 @@
wpa_config_remove_network(wpa_s->conf, id);
}
}
+
+ wpas_wps_clear_ap_info(wpa_s);
}
@@ -907,6 +913,7 @@
ssid->eap.fragment_size = wpa_s->wps_fragment_size;
eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
wpa_s, NULL);
+ wpa_s->wps_ap_iter = 1;
wpas_wps_reassoc(wpa_s, ssid, bssid);
return rpin;
}
@@ -933,7 +940,8 @@
wpa_supplicant_deauthenticate(wpa_s,
WLAN_REASON_DEAUTH_LEAVING);
wpas_clear_wps(wpa_s);
- }
+ } else
+ wpas_wps_clear_ap_info(wpa_s);
return 0;
}
@@ -1239,6 +1247,7 @@
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+ wpas_wps_clear_ap_info(wpa_s);
if (wpa_s->wps == NULL)
return;
@@ -1920,3 +1929,130 @@
}
#endif /* CONFIG_WPS_NFC */
+
+
+extern int wpa_debug_level;
+
+static void wpas_wps_dump_ap_info(struct wpa_supplicant *wpa_s)
+{
+ size_t i;
+ struct os_time now;
+
+ if (wpa_debug_level > MSG_DEBUG)
+ return;
+
+ if (wpa_s->wps_ap == NULL)
+ return;
+
+ os_get_time(&now);
+
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ struct wpa_blacklist *e = wpa_blacklist_get(wpa_s, ap->bssid);
+
+ wpa_printf(MSG_DEBUG, "WPS: AP[%d] " MACSTR " type=%d "
+ "tries=%d last_attempt=%d sec ago blacklist=%d",
+ (int) i, MAC2STR(ap->bssid), ap->type, ap->tries,
+ ap->last_attempt.sec > 0 ?
+ (int) now.sec - (int) ap->last_attempt.sec : -1,
+ e ? e->count : 0);
+ }
+}
+
+
+static struct wps_ap_info * wpas_wps_get_ap_info(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ size_t i;
+
+ if (wpa_s->wps_ap == NULL)
+ return NULL;
+
+ for (i = 0; i < wpa_s->num_wps_ap; i++) {
+ struct wps_ap_info *ap = &wpa_s->wps_ap[i];
+ if (os_memcmp(ap->bssid, bssid, ETH_ALEN) == 0)
+ return ap;
+ }
+
+ return NULL;
+}
+
+
+static void wpas_wps_update_ap_info_bss(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_res *res)
+{
+ struct wpabuf *wps;
+ enum wps_ap_info_type type;
+ struct wps_ap_info *ap;
+ int r;
+
+ if (wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE) == NULL)
+ return;
+
+ wps = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+ if (wps == NULL)
+ return;
+
+ r = wps_is_addr_authorized(wps, wpa_s->own_addr, 1);
+ if (r == 2)
+ type = WPS_AP_SEL_REG_OUR;
+ else if (r == 1)
+ type = WPS_AP_SEL_REG;
+ else
+ type = WPS_AP_NOT_SEL_REG;
+
+ wpabuf_free(wps);
+
+ ap = wpas_wps_get_ap_info(wpa_s, res->bssid);
+ if (ap) {
+ if (ap->type != type) {
+ wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR
+ " changed type %d -> %d",
+ MAC2STR(res->bssid), ap->type, type);
+ ap->type = type;
+ if (type != WPS_AP_NOT_SEL_REG)
+ wpa_blacklist_del(wpa_s, ap->bssid);
+ }
+ return;
+ }
+
+ ap = os_realloc_array(wpa_s->wps_ap, wpa_s->num_wps_ap + 1,
+ sizeof(struct wps_ap_info));
+ if (ap == NULL)
+ return;
+
+ wpa_s->wps_ap = ap;
+ ap = &wpa_s->wps_ap[wpa_s->num_wps_ap];
+ wpa_s->num_wps_ap++;
+
+ os_memset(ap, 0, sizeof(*ap));
+ os_memcpy(ap->bssid, res->bssid, ETH_ALEN);
+ ap->type = type;
+ wpa_printf(MSG_DEBUG, "WPS: AP " MACSTR " type %d added",
+ MAC2STR(ap->bssid), ap->type);
+}
+
+
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+ size_t i;
+
+ for (i = 0; i < scan_res->num; i++)
+ wpas_wps_update_ap_info_bss(wpa_s, scan_res->res[i]);
+
+ wpas_wps_dump_ap_info(wpa_s);
+}
+
+
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct wps_ap_info *ap;
+ if (!wpa_s->wps_ap_iter)
+ return;
+ ap = wpas_wps_get_ap_info(wpa_s, bssid);
+ if (ap == NULL)
+ return;
+ ap->tries++;
+ os_get_time(&ap->last_attempt);
+}
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 5a49a8f..36f1e02 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -10,6 +10,7 @@
#define WPS_SUPPLICANT_H
struct wpa_scan_res;
+struct wpa_scan_results;
#ifdef CONFIG_WPS
@@ -68,6 +69,9 @@
int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
const struct wpabuf *data);
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res);
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
#else /* CONFIG_WPS */
@@ -120,6 +124,16 @@
return 0;
}
+static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_results *scan_res)
+{
+}
+
+static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+}
+
#endif /* CONFIG_WPS */
#endif /* WPS_SUPPLICANT_H */