/*
* hostapd / Configuration file
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
#include "wpa_common.h"
#include "wpa.h"
#include "uuid.h"
+#include "eap_common/eap_wsc_common.h"
#define MAX_STA_COUNT 2007
bss->eapol_version = EAPOL_VERSION;
bss->max_listen_interval = 65535;
+
+#ifdef CONFIG_IEEE80211W
+ bss->assoc_sa_query_max_timeout = 1000;
+ bss->assoc_sa_query_retry_timeout = 201;
+#endif /* CONFIG_IEEE80211W */
+#ifdef EAP_FAST
+ /* both anonymous and authenticated provisioning */
+ bss->eap_fast_prov = 3;
+ bss->pac_key_lifetime = 7 * 24 * 60 * 60;
+ bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
+#endif /* EAP_FAST */
}
conf->wme_ac_params[2] = ac_vi;
conf->wme_ac_params[3] = ac_vo;
+#ifdef CONFIG_IEEE80211N
+ conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
+#endif /* CONFIG_IEEE80211N */
+
return conf;
}
}
-static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
- int *num)
+static int hostapd_acl_comp(const void *a, const void *b)
+{
+ const struct mac_acl_entry *aa = a;
+ const struct mac_acl_entry *bb = b;
+ return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname,
+ struct mac_acl_entry **acl, int *num)
{
FILE *f;
char buf[128], *pos;
int line = 0;
u8 addr[ETH_ALEN];
- macaddr *newacl;
+ struct mac_acl_entry *newacl;
+ int vlan_id;
if (!fname)
return 0;
return -1;
}
- newacl = os_realloc(*acl, (*num + 1) * ETH_ALEN);
+ vlan_id = 0;
+ pos = buf;
+ while (*pos != '\0' && *pos != ' ' && *pos != '\t')
+ pos++;
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ if (*pos != '\0')
+ vlan_id = atoi(pos);
+
+ newacl = os_realloc(*acl, (*num + 1) * sizeof(**acl));
if (newacl == NULL) {
printf("MAC list reallocation failed\n");
fclose(f);
}
*acl = newacl;
- os_memcpy((*acl)[*num], addr, ETH_ALEN);
+ os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+ (*acl)[*num].vlan_id = vlan_id;
(*num)++;
}
fclose(f);
- qsort(*acl, *num, sizeof(macaddr), hostapd_mac_comp);
+ qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
return 0;
}
os_memcpy(psk->addr, addr, ETH_ALEN);
pos = buf + 17;
- if (pos == '\0') {
+ if (*pos == '\0') {
printf("No PSK on line %d in '%s'\n", line, fname);
os_free(psk);
ret = -1;
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
else if (os_strcmp(start, "FT-EAP") == 0)
val |= WPA_KEY_MGMT_FT_IEEE8021X;
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+ else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+ val |= WPA_KEY_MGMT_PSK_SHA256;
+ else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
else {
printf("Line %d: invalid key_mgmt '%s'\n",
line, start);
return -1;
start = buf;
- while (start != '\0') {
+ while (*start != '\0') {
while (*start == ' ' || *start == '\t')
start++;
if (*start == '\0')
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211N
+ if (conf->ieee80211n && bss->wpa &&
+ !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+ !(bss->rsn_pairwise & WPA_CIPHER_CCMP)) {
+ printf("HT (IEEE 802.11n) with WPA/WPA2 requires CCMP to be "
+ "enabled\n");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211N */
+
return 0;
}
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211N
+static int hostapd_config_ht_capab(struct hostapd_config *conf,
+ const char *capab)
+{
+ if (os_strstr(capab, "[LDPC]"))
+ conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
+ if (os_strstr(capab, "[HT40-]")) {
+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ conf->secondary_channel = -1;
+ }
+ if (os_strstr(capab, "[HT40+]")) {
+ conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+ conf->secondary_channel = 1;
+ }
+ if (os_strstr(capab, "[SMPS-STATIC]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+ conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
+ }
+ if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+ conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
+ }
+ if (os_strstr(capab, "[GF]"))
+ conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
+ if (os_strstr(capab, "[SHORT-GI-20]"))
+ conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
+ if (os_strstr(capab, "[SHORT-GI-40]"))
+ conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
+ if (os_strstr(capab, "[TX-STBC]"))
+ conf->ht_capab |= HT_CAP_INFO_TX_STBC;
+ if (os_strstr(capab, "[RX-STBC1]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
+ }
+ if (os_strstr(capab, "[RX-STBC12]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
+ }
+ if (os_strstr(capab, "[RX-STBC123]")) {
+ conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+ conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
+ }
+ if (os_strstr(capab, "[DELAYED-BA]"))
+ conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
+ if (os_strstr(capab, "[MAX-AMSDU-7935]"))
+ conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
+ if (os_strstr(capab, "[DSSS_CCK-40]"))
+ conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
+ if (os_strstr(capab, "[PSMP]"))
+ conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
+ if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
+ conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
+
+ return 0;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
struct hostapd_config * hostapd_config_read(const char *fname)
{
struct hostapd_config *conf;
conf->country[2] = ' ';
} else if (os_strcmp(buf, "ieee80211d") == 0) {
conf->ieee80211d = atoi(pos);
- } else if (os_strcmp(buf, "ieee80211h") == 0) {
- conf->ieee80211h = atoi(pos);
- } else if (os_strcmp(buf, "assoc_ap_addr") == 0) {
- if (hwaddr_aton(pos, bss->assoc_ap_addr)) {
- printf("Line %d: invalid MAC address '%s'\n",
- line, pos);
- errors++;
- }
- bss->assoc_ap = 1;
} else if (os_strcmp(buf, "ieee8021x") == 0) {
bss->ieee802_1x = atoi(pos);
} else if (os_strcmp(buf, "eapol_version") == 0) {
errors++;
}
} else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
- os_free(bss->eap_fast_a_id);
- bss->eap_fast_a_id = os_strdup(pos);
+ size_t idlen = os_strlen(pos);
+ if (idlen & 1) {
+ printf("Line %d: Invalid eap_fast_a_id\n",
+ line);
+ errors++;
+ } else {
+ os_free(bss->eap_fast_a_id);
+ bss->eap_fast_a_id = os_malloc(idlen / 2);
+ if (bss->eap_fast_a_id == NULL ||
+ hexstr2bin(pos, bss->eap_fast_a_id,
+ idlen / 2)) {
+ printf("Line %d: Failed to parse "
+ "eap_fast_a_id\n", line);
+ errors++;
+ } else
+ bss->eap_fast_a_id_len = idlen / 2;
+ }
+ } else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
+ os_free(bss->eap_fast_a_id_info);
+ bss->eap_fast_a_id_info = os_strdup(pos);
+ } else if (os_strcmp(buf, "eap_fast_prov") == 0) {
+ bss->eap_fast_prov = atoi(pos);
+ } else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
+ bss->pac_key_lifetime = atoi(pos);
+ } else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
+ bss->pac_key_refresh_time = atoi(pos);
#endif /* EAP_FAST */
#ifdef EAP_SIM
} else if (os_strcmp(buf, "eap_sim_db") == 0) {
bss->wpa_strict_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
bss->wpa_gmk_rekey = atoi(pos);
+ } else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
+ bss->wpa_ptk_rekey = atoi(pos);
} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
int len = os_strlen(pos);
if (len < 8 || len > 63) {
printf("Line %d: invalid rate list\n", line);
errors++;
}
+ } else if (os_strcmp(buf, "preamble") == 0) {
+ if (atoi(pos))
+ conf->preamble = SHORT_PREAMBLE;
+ else
+ conf->preamble = LONG_PREAMBLE;
} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
bss->ignore_broadcast_ssid = atoi(pos);
} else if (os_strcmp(buf, "bridge_packets") == 0) {
#ifdef CONFIG_IEEE80211W
} else if (os_strcmp(buf, "ieee80211w") == 0) {
bss->ieee80211w = atoi(pos);
+ } else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
+ bss->assoc_sa_query_max_timeout = atoi(pos);
+ if (bss->assoc_sa_query_max_timeout == 0) {
+ printf("Line %d: invalid "
+ "assoc_sa_query_max_timeout\n",
+ line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
+ {
+ bss->assoc_sa_query_retry_timeout = atoi(pos);
+ if (bss->assoc_sa_query_retry_timeout == 0) {
+ printf("Line %d: invalid "
+ "assoc_sa_query_retry_timeout\n",
+ line);
+ errors++;
+ }
#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211N
+ } else if (os_strcmp(buf, "ieee80211n") == 0) {
+ conf->ieee80211n = atoi(pos);
+ } else if (os_strcmp(buf, "ht_capab") == 0) {
+ if (hostapd_config_ht_capab(conf, pos) < 0) {
+ printf("Line %d: invalid ht_capab\n", line);
+ errors++;
+ }
+#endif /* CONFIG_IEEE80211N */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
} else if (os_strcmp(buf, "okc") == 0) {
bss->okc = atoi(pos);
+#ifdef CONFIG_WPS
+ } else if (os_strcmp(buf, "wps_state") == 0) {
+ bss->wps_state = atoi(pos);
+ if (bss->wps_state < 0 || bss->wps_state > 2) {
+ printf("Line %d: invalid wps_state\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ap_setup_locked") == 0) {
+ bss->ap_setup_locked = atoi(pos);
+ } else if (os_strcmp(buf, "uuid") == 0) {
+ if (uuid_str2bin(pos, bss->uuid)) {
+ printf("Line %d: invalid UUID\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "wps_pin_requests") == 0) {
+ bss->wps_pin_requests = os_strdup(pos);
+ } else if (os_strcmp(buf, "device_name") == 0) {
+ if (os_strlen(pos) > 32) {
+ printf("Line %d: Too long device_name\n",
+ line);
+ errors++;
+ }
+ bss->device_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "manufacturer") == 0) {
+ if (os_strlen(pos) > 64) {
+ printf("Line %d: Too long manufacturer\n",
+ line);
+ errors++;
+ }
+ bss->manufacturer = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_name") == 0) {
+ if (os_strlen(pos) > 32) {
+ printf("Line %d: Too long model_name\n",
+ line);
+ errors++;
+ }
+ bss->model_name = os_strdup(pos);
+ } else if (os_strcmp(buf, "model_number") == 0) {
+ if (os_strlen(pos) > 32) {
+ printf("Line %d: Too long model_number\n",
+ line);
+ errors++;
+ }
+ bss->model_number = os_strdup(pos);
+ } else if (os_strcmp(buf, "serial_number") == 0) {
+ if (os_strlen(pos) > 32) {
+ printf("Line %d: Too long serial_number\n",
+ line);
+ errors++;
+ }
+ bss->serial_number = os_strdup(pos);
+ } else if (os_strcmp(buf, "device_type") == 0) {
+ bss->device_type = os_strdup(pos);
+ } else if (os_strcmp(buf, "config_methods") == 0) {
+ bss->config_methods = os_strdup(pos);
+ } else if (os_strcmp(buf, "os_version") == 0) {
+ if (hexstr2bin(pos, bss->os_version, 4)) {
+ printf("Line %d: invalid os_version\n", line);
+ errors++;
+ }
+ } else if (os_strcmp(buf, "ap_pin") == 0) {
+ bss->ap_pin = os_strdup(pos);
+#endif /* CONFIG_WPS */
} else {
printf("Line %d: unknown configuration item '%s'\n",
line, buf);
os_free(conf->dh_file);
os_free(conf->pac_opaque_encr_key);
os_free(conf->eap_fast_a_id);
+ os_free(conf->eap_fast_a_id_info);
os_free(conf->eap_sim_db);
os_free(conf->radius_server_clients);
os_free(conf->test_socket);
}
}
#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_WPS
+ os_free(conf->wps_pin_requests);
+ os_free(conf->device_name);
+ os_free(conf->manufacturer);
+ os_free(conf->model_name);
+ os_free(conf->model_number);
+ os_free(conf->serial_number);
+ os_free(conf->device_type);
+ os_free(conf->config_methods);
+ os_free(conf->ap_pin);
+#endif /* CONFIG_WPS */
}
+/**
+ * hostapd_config_free - Free hostapd configuration
+ * @conf: Configuration data from hostapd_config_read().
+ */
void hostapd_config_free(struct hostapd_config *conf)
{
size_t i;
}
-/* Perform a binary search for given MAC address from a pre-sorted list.
- * Returns 1 if address is in the list or 0 if not. */
-int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr)
+/**
+ * hostapd_maclist_found - Find a MAC address from a list
+ * @list: MAC address list
+ * @num_entries: Number of addresses in the list
+ * @addr: Address to search for
+ * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
+ * Returns: 1 if address is in the list or 0 if not.
+ *
+ * Perform a binary search for given MAC address from a pre-sorted list.
+ */
+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
+ const u8 *addr, int *vlan_id)
{
int start, end, middle, res;
while (start <= end) {
middle = (start + end) / 2;
- res = os_memcmp(list[middle], addr, ETH_ALEN);
- if (res == 0)
+ res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
+ if (res == 0) {
+ if (vlan_id)
+ *vlan_id = list[middle].vlan_id;
return 1;
+ }
if (res < 0)
start = middle + 1;
else
{
struct hostapd_eap_user *user = conf->eap_user;
+#ifdef CONFIG_WPS
+ if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+ os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+ static struct hostapd_eap_user wsc_enrollee;
+ os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+ wsc_enrollee.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_enrollee.methods[0].vendor);
+ return &wsc_enrollee;
+ }
+
+ if (conf->wps_state && conf->ap_pin &&
+ identity_len == WSC_ID_REGISTRAR_LEN &&
+ os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+ static struct hostapd_eap_user wsc_registrar;
+ os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+ wsc_registrar.methods[0].method = eap_server_get_type(
+ "WSC", &wsc_registrar.methods[0].vendor);
+ wsc_registrar.password = (u8 *) conf->ap_pin;
+ wsc_registrar.password_len = os_strlen(conf->ap_pin);
+ return &wsc_registrar;
+ }
+#endif /* CONFIG_WPS */
+
while (user) {
if (!phase2 && user->identity == NULL) {
/* Wildcard match */