Moved association check from driver_*.c into ieee802_1x_receive()
[wpasupplicant] / hostapd / config.c
index 7fceacb..c760ee6 100644 (file)
@@ -26,6 +26,7 @@
 #include "wpa_common.h"
 #include "wpa.h"
 #include "uuid.h"
+#include "eap_common/eap_wsc_common.h"
 
 
 #define MAX_STA_COUNT 2007
@@ -183,8 +184,8 @@ static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
        bss->max_listen_interval = 65535;
 
 #ifdef CONFIG_IEEE80211W
-       bss->assoc_ping_timeout = 1000;
-       bss->assoc_ping_attempts = 3;
+       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 */
@@ -257,11 +258,7 @@ static struct hostapd_config * hostapd_config_defaults(void)
        conf->wme_ac_params[3] = ac_vo;
 
 #ifdef CONFIG_IEEE80211N
-       SET_2BIT_LE16(&conf->ht_capab,
-                     HT_CAP_INFO_MIMO_PWR_SAVE_OFFSET,
-                     MIMO_PWR_NO_LIMIT_ON_MIMO_SEQS);
-
-       conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
+       conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
 #endif /* CONFIG_IEEE80211N */
 
        return conf;
@@ -414,7 +411,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
                        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;
@@ -803,7 +800,7 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
                return -1;
        start = buf;
 
-       while (start != '\0') {
+       while (*start != '\0') {
                while (*start == ' ' || *start == '\t')
                        start++;
                if (*start == '\0')
@@ -861,7 +858,7 @@ static int hostapd_config_parse_cipher(int line, const char *value)
                return -1;
        start = buf;
 
-       while (start != '\0') {
+       while (*start != '\0') {
                while (*start == ' ' || *start == '\t')
                        start++;
                if (*start == '\0')
@@ -947,6 +944,16 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
        }
 #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;
 }
 
@@ -1312,6 +1319,69 @@ static int add_r1kh(struct hostapd_bss_config *bss, char *value)
 #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;
@@ -1445,15 +1515,6 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        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) {
@@ -1697,6 +1758,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                        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) {
@@ -2006,18 +2069,20 @@ struct hostapd_config * hostapd_config_read(const char *fname)
 #ifdef CONFIG_IEEE80211W
                } else if (os_strcmp(buf, "ieee80211w") == 0) {
                        bss->ieee80211w = atoi(pos);
-               } else if (os_strcmp(buf, "assoc_ping_timeout") == 0) {
-                       bss->assoc_ping_timeout = atoi(pos);
-                       if (bss->assoc_ping_timeout == 0) {
-                               printf("Line %d: invalid assoc_ping_timeout\n",
-                                       line);
+               } 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_ping_attempts") == 0) {
-                       bss->assoc_ping_timeout = atoi(pos);
-                       if (bss->assoc_ping_timeout == 0) {
-                               printf("Line %d: invalid assoc_ping_attempts "
-                                      "(valid range: 1..255)\n",
+               } 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++;
                        }
@@ -2025,11 +2090,79 @@ struct hostapd_config * hostapd_config_read(const char *fname)
 #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);
@@ -2223,9 +2356,25 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
                }
        }
 #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;
@@ -2241,8 +2390,16 @@ void hostapd_config_free(struct hostapd_config *conf)
 }
 
 
-/* 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. */
+/**
+ * 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)
 {
@@ -2321,6 +2478,29 @@ hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
 {
        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 */