hostapd: Use stations nsts capability in (Re)Association Response frame
[mech_eap.git] / hostapd / config_file.c
index 5f84281..fa08234 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Configuration file parser
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -97,6 +97,8 @@ static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
                }
 
                vlan->vlan_id = vlan_id;
+               vlan->vlan_desc.untagged = vlan_id;
+               vlan->vlan_desc.notempty = !!vlan_id;
                os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
                vlan->next = bss->vlan;
                bss->vlan = vlan;
@@ -197,7 +199,10 @@ static int hostapd_config_read_maclist(const char *fname,
 
                *acl = newacl;
                os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
-               (*acl)[*num].vlan_id = vlan_id;
+               os_memset(&(*acl)[*num].vlan_id, 0,
+                         sizeof((*acl)[*num].vlan_id));
+               (*acl)[*num].vlan_id.untagged = vlan_id;
+               (*acl)[*num].vlan_id.notempty = !!vlan_id;
                (*num)++;
        }
 
@@ -216,15 +221,21 @@ static int hostapd_config_read_eap_user(const char *fname,
        FILE *f;
        char buf[512], *pos, *start, *pos2;
        int line = 0, ret = 0, num_methods;
-       struct hostapd_eap_user *user = NULL, *tail = NULL;
+       struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
 
        if (!fname)
                return 0;
 
        if (os_strncmp(fname, "sqlite:", 7) == 0) {
+#ifdef CONFIG_SQLITE
                os_free(conf->eap_user_sqlite);
                conf->eap_user_sqlite = os_strdup(fname + 7);
                return 0;
+#else /* CONFIG_SQLITE */
+               wpa_printf(MSG_ERROR,
+                          "EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
+               return -1;
+#endif /* CONFIG_SQLITE */
        }
 
        f = fopen(fname, "r");
@@ -494,7 +505,7 @@ static int hostapd_config_read_eap_user(const char *fname,
 
        done:
                if (tail == NULL) {
-                       tail = conf->eap_user = user;
+                       tail = new_user = user;
                } else {
                        tail->next = user;
                        tail = user;
@@ -510,6 +521,18 @@ static int hostapd_config_read_eap_user(const char *fname,
 
        fclose(f);
 
+       if (ret == 0) {
+               user = conf->eap_user;
+               while (user) {
+                       struct hostapd_eap_user *prev;
+
+                       prev = user;
+                       user = user->next;
+                       hostapd_config_free_eap_user(prev);
+               }
+               conf->eap_user = new_user;
+       }
+
        return ret;
 }
 #endif /* EAP_SERVER */
@@ -613,8 +636,7 @@ hostapd_parse_radius_attr(const char *value)
 }
 
 
-static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
-                                   const char *val)
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss, char *val)
 {
        char *secret;
 
@@ -622,7 +644,7 @@ static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
        if (secret == NULL)
                return -1;
 
-       secret++;
+       *secret++ = '\0';
 
        if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
                return -1;
@@ -680,6 +702,14 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
                else if (os_strcmp(start, "FT-SAE") == 0)
                        val |= WPA_KEY_MGMT_FT_SAE;
 #endif /* CONFIG_SAE */
+#ifdef CONFIG_SUITEB
+               else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+                       val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+               else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+                       val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
                else {
                        wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
                                   line, start);
@@ -755,6 +785,24 @@ static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
 }
 
 
+static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
+{
+       char *pos;
+
+       /* for backwards compatibility, translate ' ' in conf str to ',' */
+       pos = val;
+       while (pos) {
+               pos = os_strchr(pos, ' ');
+               if (pos)
+                       *pos++ = ',';
+       }
+       if (freq_range_list_parse(&conf->acs_ch_list, val))
+               return -1;
+
+       return 0;
+}
+
+
 static int hostapd_parse_intlist(int **int_list, char *val)
 {
        int *list;
@@ -855,7 +903,9 @@ static int hostapd_config_read_int10(const char *value)
 static int valid_cw(int cw)
 {
        return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
-               cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+               cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023 ||
+               cw == 2047 || cw == 4095 || cw == 8191 || cw == 16383 ||
+               cw == 32767);
 }
 
 
@@ -866,11 +916,11 @@ enum {
        IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
 };
 
-static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
-                                  char *val)
+static int hostapd_config_tx_queue(struct hostapd_config *conf,
+                                  const char *name, const char *val)
 {
        int num;
-       char *pos;
+       const char *pos;
        struct hostapd_tx_queue_params *queue;
 
        /* skip 'tx_queue_' prefix */
@@ -1114,13 +1164,23 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
        if (os_strstr(capab, "[BF-ANTENNA-2]") &&
            (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
                conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+       if (os_strstr(capab, "[BF-ANTENNA-3]") &&
+           (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+               conf->vht_capab |= (2 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
+       if (os_strstr(capab, "[BF-ANTENNA-4]") &&
+           (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+               conf->vht_capab |= (3 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
        if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
            (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
                conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
+       if (os_strstr(capab, "[SOUNDING-DIMENSION-3]") &&
+           (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+               conf->vht_capab |= (2 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
+       if (os_strstr(capab, "[SOUNDING-DIMENSION-4]") &&
+           (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+               conf->vht_capab |= (3 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
        if (os_strstr(capab, "[MU-BEAMFORMER]"))
                conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
-       if (os_strstr(capab, "[MU-BEAMFORMEE]"))
-               conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
        if (os_strstr(capab, "[VHT-TXOP-PS]"))
                conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
        if (os_strstr(capab, "[HTC-VHT]"))
@@ -1463,6 +1523,54 @@ fail:
 }
 
 
+static int parse_anqp_elem(struct hostapd_bss_config *bss, char *buf, int line)
+{
+       char *delim;
+       u16 infoid;
+       size_t len;
+       struct wpabuf *payload;
+       struct anqp_element *elem;
+
+       delim = os_strchr(buf, ':');
+       if (!delim)
+               return -1;
+       delim++;
+       infoid = atoi(buf);
+       len = os_strlen(delim);
+       if (len & 1)
+               return -1;
+       len /= 2;
+       payload = wpabuf_alloc(len);
+       if (!payload)
+               return -1;
+       if (hexstr2bin(delim, wpabuf_put(payload, len), len) < 0) {
+               wpabuf_free(payload);
+               return -1;
+       }
+
+       dl_list_for_each(elem, &bss->anqp_elem, struct anqp_element, list) {
+               if (elem->infoid == infoid) {
+                       /* Update existing entry */
+                       wpabuf_free(elem->payload);
+                       elem->payload = payload;
+                       return 0;
+               }
+       }
+
+       /* Add a new entry */
+       elem = os_zalloc(sizeof(*elem));
+       if (!elem) {
+               wpabuf_free(payload);
+               return -1;
+       }
+       elem->infoid = infoid;
+       elem->payload = payload;
+       dl_list_add(&bss->anqp_elem, &elem->list);
+
+       return 0;
+}
+
+
 static int parse_qos_map_set(struct hostapd_bss_config *bss,
                             char *buf, int line)
 {
@@ -1679,7 +1787,7 @@ static int hs20_parse_osu_ssid(struct hostapd_bss_config *bss,
        char *str;
 
        str = wpa_config_parse_string(pos, &slen);
-       if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+       if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
                wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
                os_free(str);
                return -1;
@@ -1811,34 +1919,76 @@ static int hs20_parse_osu_service_desc(struct hostapd_bss_config *bss,
 #endif /* CONFIG_HS20 */
 
 
-#ifdef CONFIG_WPS_NFC
-static struct wpabuf * hostapd_parse_bin(const char *buf)
+#ifdef CONFIG_ACS
+static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
+                                             char *pos)
 {
-       size_t len;
-       struct wpabuf *ret;
+       struct acs_bias *bias = NULL, *tmp;
+       unsigned int num = 0;
+       char *end;
 
-       len = os_strlen(buf);
-       if (len & 0x01)
-               return NULL;
-       len /= 2;
+       while (*pos) {
+               tmp = os_realloc_array(bias, num + 1, sizeof(*bias));
+               if (!tmp)
+                       goto fail;
+               bias = tmp;
 
-       ret = wpabuf_alloc(len);
-       if (ret == NULL)
-               return NULL;
+               bias[num].channel = atoi(pos);
+               if (bias[num].channel <= 0)
+                       goto fail;
+               pos = os_strchr(pos, ':');
+               if (!pos)
+                       goto fail;
+               pos++;
+               bias[num].bias = strtod(pos, &end);
+               if (end == pos || bias[num].bias < 0.0)
+                       goto fail;
+               pos = end;
+               if (*pos != ' ' && *pos != '\0')
+                       goto fail;
+               num++;
+       }
 
-       if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
-               wpabuf_free(ret);
-               return NULL;
+       os_free(conf->acs_chan_bias);
+       conf->acs_chan_bias = bias;
+       conf->num_acs_chan_bias = num;
+
+       return 0;
+fail:
+       os_free(bias);
+       return -1;
+}
+#endif /* CONFIG_ACS */
+
+
+static int parse_wpabuf_hex(int line, const char *name, struct wpabuf **buf,
+                           const char *val)
+{
+       struct wpabuf *elems;
+
+       if (val[0] == '\0') {
+               wpabuf_free(*buf);
+               *buf = NULL;
+               return 0;
        }
 
-       return ret;
+       elems = wpabuf_parse_bin(val);
+       if (!elems) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid %s '%s'",
+                          line, name, val);
+               return -1;
+       }
+
+       wpabuf_free(*buf);
+       *buf = elems;
+
+       return 0;
 }
-#endif /* CONFIG_WPS_NFC */
 
 
 static int hostapd_config_fill(struct hostapd_config *conf,
                               struct hostapd_bss_config *bss,
-                              char *buf, char *pos, int line)
+                              const char *buf, char *pos, int line)
 {
        if (os_strcmp(buf, "interface") == 0) {
                os_strlcpy(conf->bss[0]->iface, pos,
@@ -1865,6 +2015,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   line, pos);
                        return 1;
                }
+       } else if (os_strcmp(buf, "driver_params") == 0) {
+               os_free(conf->driver_params);
+               conf->driver_params = os_strdup(pos);
        } else if (os_strcmp(buf, "debug") == 0) {
                wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' configuration variable is not used anymore",
                           line);
@@ -1881,7 +2034,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                           line);
        } else if (os_strcmp(buf, "ssid") == 0) {
                bss->ssid.ssid_len = os_strlen(pos);
-               if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+               if (bss->ssid.ssid_len > SSID_MAX_LEN ||
                    bss->ssid.ssid_len < 1) {
                        wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
                                   line, pos);
@@ -1892,7 +2045,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "ssid2") == 0) {
                size_t slen;
                char *str = wpa_config_parse_string(pos, &slen);
-               if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+               if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
                        wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
                                   line, pos);
                        os_free(str);
@@ -1978,12 +2131,20 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->private_key_passwd = os_strdup(pos);
        } else if (os_strcmp(buf, "check_crl") == 0) {
                bss->check_crl = atoi(pos);
+       } else if (os_strcmp(buf, "tls_session_lifetime") == 0) {
+               bss->tls_session_lifetime = atoi(pos);
        } else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
                os_free(bss->ocsp_stapling_response);
                bss->ocsp_stapling_response = os_strdup(pos);
+       } else if (os_strcmp(buf, "ocsp_stapling_response_multi") == 0) {
+               os_free(bss->ocsp_stapling_response_multi);
+               bss->ocsp_stapling_response_multi = os_strdup(pos);
        } else if (os_strcmp(buf, "dh_file") == 0) {
                os_free(bss->dh_file);
                bss->dh_file = os_strdup(pos);
+       } else if (os_strcmp(buf, "openssl_ciphers") == 0) {
+               os_free(bss->openssl_ciphers);
+               bss->openssl_ciphers = os_strdup(pos);
        } else if (os_strcmp(buf, "fragment_size") == 0) {
                bss->fragment_size = atoi(pos);
 #ifdef EAP_SERVER_FAST
@@ -2033,6 +2194,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "eap_sim_db") == 0) {
                os_free(bss->eap_sim_db);
                bss->eap_sim_db = os_strdup(pos);
+       } else if (os_strcmp(buf, "eap_sim_db_timeout") == 0) {
+               bss->eap_sim_db_timeout = atoi(pos);
        } else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
                bss->eap_sim_aka_result_ind = atoi(pos);
 #endif /* EAP_SERVER_SIM */
@@ -2044,6 +2207,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "pwd_group") == 0) {
                bss->pwd_group = atoi(pos);
 #endif /* EAP_SERVER_PWD */
+       } else if (os_strcmp(buf, "eap_server_erp") == 0) {
+               bss->eap_server_erp = atoi(pos);
 #endif /* EAP_SERVER */
        } else if (os_strcmp(buf, "eap_message") == 0) {
                char *term;
@@ -2063,6 +2228,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   (term - bss->eap_req_id_text) - 1);
                        bss->eap_req_id_text_len--;
                }
+       } else if (os_strcmp(buf, "erp_send_reauth_start") == 0) {
+               bss->erp_send_reauth_start = atoi(pos);
+       } else if (os_strcmp(buf, "erp_domain") == 0) {
+               os_free(bss->erp_domain);
+               bss->erp_domain = os_strdup(pos);
        } else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
                bss->default_wep_key_len = atoi(pos);
                if (bss->default_wep_key_len > 13) {
@@ -2114,6 +2284,14 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                os_free(bss->nas_identifier);
                bss->nas_identifier = os_strdup(pos);
 #ifndef CONFIG_NO_RADIUS
+       } else if (os_strcmp(buf, "radius_client_addr") == 0) {
+               if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: invalid IP address '%s'",
+                                  line, pos);
+                       return 1;
+               }
+               bss->radius->force_client_addr = 1;
        } else if (os_strcmp(buf, "auth_server_addr") == 0) {
                if (hostapd_config_read_radius_addr(
                            &bss->radius->auth_servers,
@@ -2125,6 +2303,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
                }
        } else if (bss->radius->auth_server &&
+                  os_strcmp(buf, "auth_server_addr_replace") == 0) {
+               if (hostapd_parse_ip_addr(pos,
+                                         &bss->radius->auth_server->addr)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: invalid IP address '%s'",
+                                  line, pos);
+                       return 1;
+               }
+       } else if (bss->radius->auth_server &&
                   os_strcmp(buf, "auth_server_port") == 0) {
                bss->radius->auth_server->port = atoi(pos);
        } else if (bss->radius->auth_server &&
@@ -2150,6 +2337,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
                }
        } else if (bss->radius->acct_server &&
+                  os_strcmp(buf, "acct_server_addr_replace") == 0) {
+               if (hostapd_parse_ip_addr(pos,
+                                         &bss->radius->acct_server->addr)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: invalid IP address '%s'",
+                                  line, pos);
+                       return 1;
+               }
+       } else if (bss->radius->acct_server &&
                   os_strcmp(buf, "acct_server_port") == 0) {
                bss->radius->acct_server->port = atoi(pos);
        } else if (bss->radius->acct_server &&
@@ -2214,6 +2410,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->radius_das_time_window = atoi(pos);
        } else if (os_strcmp(buf, "radius_das_require_event_timestamp") == 0) {
                bss->radius_das_require_event_timestamp = atoi(pos);
+       } else if (os_strcmp(buf, "radius_das_require_message_authenticator") ==
+                  0) {
+               bss->radius_das_require_message_authenticator = atoi(pos);
 #endif /* CONFIG_NO_RADIUS */
        } else if (os_strcmp(buf, "auth_algs") == 0) {
                bss->auth_algs = atoi(pos);
@@ -2250,12 +2449,11 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                os_free(bss->ssid.wpa_passphrase);
                bss->ssid.wpa_passphrase = os_strdup(pos);
                if (bss->ssid.wpa_passphrase) {
-                       os_free(bss->ssid.wpa_psk);
-                       bss->ssid.wpa_psk = NULL;
+                       hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
                        bss->ssid.wpa_passphrase_set = 1;
                }
        } else if (os_strcmp(buf, "wpa_psk") == 0) {
-               os_free(bss->ssid.wpa_psk);
+               hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
                bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
                if (bss->ssid.wpa_psk == NULL)
                        return 1;
@@ -2263,8 +2461,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                    pos[PMK_LEN * 2] != '\0') {
                        wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
                                   line, pos);
-                       os_free(bss->ssid.wpa_psk);
-                       bss->ssid.wpa_psk = NULL;
+                       hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
                        return 1;
                }
                bss->ssid.wpa_psk->group = 1;
@@ -2405,9 +2602,6 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
                bss->radius_server_ipv6 = atoi(pos);
 #endif /* RADIUS_SERVER */
-       } else if (os_strcmp(buf, "test_socket") == 0) {
-               os_free(bss->test_socket);
-               bss->test_socket = os_strdup(pos);
        } else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
                bss->use_pae_group_addr = atoi(pos);
        } else if (os_strcmp(buf, "hw_mode") == 0) {
@@ -2419,13 +2613,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
                else if (os_strcmp(pos, "ad") == 0)
                        conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+               else if (os_strcmp(pos, "any") == 0)
+                       conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
                else {
                        wpa_printf(MSG_ERROR, "Line %d: unknown hw_mode '%s'",
                                   line, pos);
                        return 1;
                }
        } else if (os_strcmp(buf, "wps_rf_bands") == 0) {
-               if (os_strcmp(pos, "a") == 0)
+               if (os_strcmp(pos, "ad") == 0)
+                       bss->wps_rf_bands = WPS_RF_60GHZ;
+               else if (os_strcmp(pos, "a") == 0)
                        bss->wps_rf_bands = WPS_RF_50GHZ;
                else if (os_strcmp(pos, "g") == 0 ||
                         os_strcmp(pos, "b") == 0)
@@ -2445,12 +2643,16 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        wpa_printf(MSG_ERROR, "Line %d: tries to enable ACS but CONFIG_ACS disabled",
                                   line);
                        return 1;
-#endif /* CONFIG_ACS */
+#else /* CONFIG_ACS */
+                       conf->acs = 1;
                        conf->channel = 0;
-               } else
+#endif /* CONFIG_ACS */
+               } else {
                        conf->channel = atoi(pos);
+                       conf->acs = conf->channel == 0;
+               }
        } else if (os_strcmp(buf, "chanlist") == 0) {
-               if (hostapd_parse_intlist(&conf->chanlist, pos)) {
+               if (hostapd_parse_chanlist(conf, pos)) {
                        wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
                                   line);
                        return 1;
@@ -2477,6 +2679,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
                }
                conf->acs_num_scans = val;
+       } else if (os_strcmp(buf, "acs_chan_bias") == 0) {
+               if (hostapd_config_parse_acs_chan_bias(conf, pos)) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias",
+                                  line);
+                       return -1;
+               }
 #endif /* CONFIG_ACS */
        } else if (os_strcmp(buf, "dtim_period") == 0) {
                bss->dtim_period = atoi(pos);
@@ -2485,9 +2693,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   line, bss->dtim_period);
                        return 1;
                }
+       } else if (os_strcmp(buf, "bss_load_update_period") == 0) {
+               bss->bss_load_update_period = atoi(pos);
+               if (bss->bss_load_update_period < 0 ||
+                   bss->bss_load_update_period > 100) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: invalid bss_load_update_period %d",
+                                  line, bss->bss_load_update_period);
+                       return 1;
+               }
        } else if (os_strcmp(buf, "rts_threshold") == 0) {
                conf->rts_threshold = atoi(pos);
-               if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
+               if (conf->rts_threshold < -1 || conf->rts_threshold > 65535) {
                        wpa_printf(MSG_ERROR,
                                   "Line %d: invalid rts_threshold %d",
                                   line, conf->rts_threshold);
@@ -2495,8 +2712,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                }
        } else if (os_strcmp(buf, "fragm_threshold") == 0) {
                conf->fragm_threshold = atoi(pos);
-               if (conf->fragm_threshold < 256 ||
-                   conf->fragm_threshold > 2346) {
+               if (conf->fragm_threshold == -1) {
+                       /* allow a value of -1 */
+               } else if (conf->fragm_threshold < 256 ||
+                          conf->fragm_threshold > 2346) {
                        wpa_printf(MSG_ERROR,
                                   "Line %d: invalid fragm_threshold %d",
                                   line, conf->fragm_threshold);
@@ -2529,6 +2748,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        conf->preamble = LONG_PREAMBLE;
        } else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
                bss->ignore_broadcast_ssid = atoi(pos);
+       } else if (os_strcmp(buf, "no_probe_resp_if_max_sta") == 0) {
+               bss->no_probe_resp_if_max_sta = atoi(pos);
        } else if (os_strcmp(buf, "wep_default_key") == 0) {
                bss->ssid.wep.idx = atoi(pos);
                if (bss->ssid.wep.idx > 3) {
@@ -2550,6 +2771,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 #ifndef CONFIG_NO_VLAN
        } else if (os_strcmp(buf, "dynamic_vlan") == 0) {
                bss->ssid.dynamic_vlan = atoi(pos);
+       } else if (os_strcmp(buf, "per_sta_vif") == 0) {
+               bss->ssid.per_sta_vif = atoi(pos);
        } else if (os_strcmp(buf, "vlan_file") == 0) {
                if (hostapd_config_read_vlan_file(bss, pos)) {
                        wpa_printf(MSG_ERROR, "Line %d: failed to read VLAN file '%s'",
@@ -2605,6 +2828,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                   line);
                        return 1;
                }
+       } else if (os_strcmp(buf, "use_driver_iface_addr") == 0) {
+               conf->use_driver_iface_addr = atoi(pos);
 #ifdef CONFIG_IEEE80211W
        } else if (os_strcmp(buf, "ieee80211w") == 0) {
                bss->ieee80211w = atoi(pos);
@@ -2668,6 +2893,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
        } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
                conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+       } else if (os_strcmp(buf, "vendor_vht") == 0) {
+               bss->vendor_vht = atoi(pos);
+       } else if (os_strcmp(buf, "use_sta_nsts") == 0) {
+               bss->use_sta_nsts = atoi(pos);
 #endif /* CONFIG_IEEE80211AC */
        } else if (os_strcmp(buf, "max_listen_interval") == 0) {
                bss->max_listen_interval = atoi(pos);
@@ -2696,7 +2925,7 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                os_free(bss->wps_pin_requests);
                bss->wps_pin_requests = os_strdup(pos);
        } else if (os_strcmp(buf, "device_name") == 0) {
-               if (os_strlen(pos) > 32) {
+               if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
                        wpa_printf(MSG_ERROR, "Line %d: Too long "
                                   "device_name", line);
                        return 1;
@@ -2806,15 +3035,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                bss->wps_nfc_pw_from_config = 1;
        } else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
                wpabuf_free(bss->wps_nfc_dh_pubkey);
-               bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+               bss->wps_nfc_dh_pubkey = wpabuf_parse_bin(pos);
                bss->wps_nfc_pw_from_config = 1;
        } else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
                wpabuf_free(bss->wps_nfc_dh_privkey);
-               bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+               bss->wps_nfc_dh_privkey = wpabuf_parse_bin(pos);
                bss->wps_nfc_pw_from_config = 1;
        } else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
                wpabuf_free(bss->wps_nfc_dev_pw);
-               bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+               bss->wps_nfc_dev_pw = wpabuf_parse_bin(pos);
                bss->wps_nfc_pw_from_config = 1;
 #endif /* CONFIG_WPS_NFC */
 #endif /* CONFIG_WPS */
@@ -2977,6 +3206,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "nai_realm") == 0) {
                if (parse_nai_realm(bss, pos, line) < 0)
                        return 1;
+       } else if (os_strcmp(buf, "anqp_elem") == 0) {
+               if (parse_anqp_elem(bss, pos, line) < 0)
+                       return 1;
        } else if (os_strcmp(buf, "gas_frag_limit") == 0) {
                bss->gas_frag_limit = atoi(pos);
        } else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
@@ -2990,11 +3222,17 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                os_free(bss->dump_msk_file);
                bss->dump_msk_file = os_strdup(pos);
 #endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_PROXYARP
+       } else if (os_strcmp(buf, "proxy_arp") == 0) {
+               bss->proxy_arp = atoi(pos);
+#endif /* CONFIG_PROXYARP */
 #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, "na_mcast_to_ucast") == 0) {
+               bss->na_mcast_to_ucast = atoi(pos);
        } else if (os_strcmp(buf, "osen") == 0) {
                bss->osen = atoi(pos);
        } else if (os_strcmp(buf, "anqp_domain_id") == 0) {
@@ -3068,14 +3306,18 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        } else if (os_strcmp(buf, "subscr_remediation_method") == 0) {
                bss->subscr_remediation_method = atoi(pos);
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_MBO
+       } else if (os_strcmp(buf, "mbo") == 0) {
+               bss->mbo_enabled = atoi(pos);
+#endif /* CONFIG_MBO */
 #ifdef CONFIG_TESTING_OPTIONS
 #define PARSE_TEST_PROBABILITY(_val)                           \
        } else if (os_strcmp(buf, #_val) == 0) {                \
                char *end;                                      \
                                                                \
                conf->_val = strtod(pos, &end);                 \
-               if (*end || conf->_val < 0.0d ||                \
-                   conf->_val > 1.0d) {                        \
+               if (*end || conf->_val < 0.0 ||                 \
+                   conf->_val > 1.0) {                         \
                        wpa_printf(MSG_ERROR,                   \
                                   "Line %d: Invalid value '%s'", \
                                   line, pos);                  \
@@ -3086,6 +3328,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
        PARSE_TEST_PROBABILITY(ignore_assoc_probability)
        PARSE_TEST_PROBABILITY(ignore_reassoc_probability)
        PARSE_TEST_PROBABILITY(corrupt_gtk_rekey_mic_probability)
+       } else if (os_strcmp(buf, "ecsa_ie_only") == 0) {
+               conf->ecsa_ie_only = atoi(pos);
        } else if (os_strcmp(buf, "bss_load_test") == 0) {
                WPA_PUT_LE16(bss->bss_load_test, atoi(pos));
                pos = os_strchr(pos, ':');
@@ -3105,37 +3349,41 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                pos++;
                WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
                bss->bss_load_test_set = 1;
-#endif /* CONFIG_TESTING_OPTIONS */
-       } 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;
-               }
+       } else if (os_strcmp(buf, "radio_measurements") == 0) {
+               /*
+                * DEPRECATED: This parameter will be removed in the future.
+                * Use rrm_neighbor_report instead.
+                */
+               int val = atoi(pos);
 
-               elems = wpabuf_alloc(len);
-               if (elems == NULL)
+               if (val & BIT(0))
+                       bss->radio_measurements[0] |=
+                               WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+       } else if (os_strcmp(buf, "own_ie_override") == 0) {
+               struct wpabuf *tmp;
+               size_t len = os_strlen(pos) / 2;
+
+               tmp = wpabuf_alloc(len);
+               if (!tmp)
                        return 1;
 
-               if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
-                       wpabuf_free(elems);
+               if (hexstr2bin(pos, wpabuf_put(tmp, len), len)) {
+                       wpabuf_free(tmp);
                        wpa_printf(MSG_ERROR,
-                                  "Line %d: Invalid vendor_elements '%s'",
+                                  "Line %d: Invalid own_ie_override '%s'",
                                   line, pos);
                        return 1;
                }
 
-               wpabuf_free(bss->vendor_elements);
-               bss->vendor_elements = elems;
+               wpabuf_free(bss->own_ie_override);
+               bss->own_ie_override = tmp;
+#endif /* CONFIG_TESTING_OPTIONS */
+       } else if (os_strcmp(buf, "vendor_elements") == 0) {
+               if (parse_wpabuf_hex(line, buf, &bss->vendor_elements, pos))
+                       return 1;
+       } else if (os_strcmp(buf, "assocresp_elements") == 0) {
+               if (parse_wpabuf_hex(line, buf, &bss->assocresp_elements, pos))
+                       return 1;
        } else if (os_strcmp(buf, "sae_anti_clogging_threshold") == 0) {
                bss->sae_anti_clogging_threshold = atoi(pos);
        } else if (os_strcmp(buf, "sae_groups") == 0) {
@@ -3155,6 +3403,90 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                conf->local_pwr_constraint = val;
        } else if (os_strcmp(buf, "spectrum_mgmt_required") == 0) {
                conf->spectrum_mgmt_required = atoi(pos);
+       } else if (os_strcmp(buf, "wowlan_triggers") == 0) {
+               os_free(bss->wowlan_triggers);
+               bss->wowlan_triggers = os_strdup(pos);
+#ifdef CONFIG_FST
+       } else if (os_strcmp(buf, "fst_group_id") == 0) {
+               size_t len = os_strlen(pos);
+
+               if (!len || len >= sizeof(conf->fst_cfg.group_id)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Invalid fst_group_id value '%s'",
+                                  line, pos);
+                       return 1;
+               }
+
+               if (conf->fst_cfg.group_id[0]) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Duplicate fst_group value '%s'",
+                                  line, pos);
+                       return 1;
+               }
+
+               os_strlcpy(conf->fst_cfg.group_id, pos,
+                          sizeof(conf->fst_cfg.group_id));
+       } else if (os_strcmp(buf, "fst_priority") == 0) {
+               char *endp;
+               long int val;
+
+               if (!*pos) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: fst_priority value not supplied (expected 1..%u)",
+                                  line, FST_MAX_PRIO_VALUE);
+                       return -1;
+               }
+
+               val = strtol(pos, &endp, 0);
+               if (*endp || val < 1 || val > FST_MAX_PRIO_VALUE) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Invalid fst_priority %ld (%s) (expected 1..%u)",
+                                  line, val, pos, FST_MAX_PRIO_VALUE);
+                       return 1;
+               }
+               conf->fst_cfg.priority = (u8) val;
+       } else if (os_strcmp(buf, "fst_llt") == 0) {
+               char *endp;
+               long int val;
+
+               if (!*pos) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: fst_llt value not supplied (expected 1..%u)",
+                                  line, FST_MAX_LLT_MS);
+                       return -1;
+               }
+               val = strtol(pos, &endp, 0);
+               if (*endp || val < 1 ||
+                   (unsigned long int) val > FST_MAX_LLT_MS) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Invalid fst_llt %ld (%s) (expected 1..%u)",
+                                  line, val, pos, FST_MAX_LLT_MS);
+                       return 1;
+               }
+               conf->fst_cfg.llt = (u32) val;
+#endif /* CONFIG_FST */
+       } else if (os_strcmp(buf, "track_sta_max_num") == 0) {
+               conf->track_sta_max_num = atoi(pos);
+       } else if (os_strcmp(buf, "track_sta_max_age") == 0) {
+               conf->track_sta_max_age = atoi(pos);
+       } else if (os_strcmp(buf, "no_probe_resp_if_seen_on") == 0) {
+               os_free(bss->no_probe_resp_if_seen_on);
+               bss->no_probe_resp_if_seen_on = os_strdup(pos);
+       } else if (os_strcmp(buf, "no_auth_if_seen_on") == 0) {
+               os_free(bss->no_auth_if_seen_on);
+               bss->no_auth_if_seen_on = os_strdup(pos);
+       } else if (os_strcmp(buf, "lci") == 0) {
+               wpabuf_free(conf->lci);
+               conf->lci = wpabuf_parse_bin(pos);
+       } else if (os_strcmp(buf, "civic") == 0) {
+               wpabuf_free(conf->civic);
+               conf->civic = wpabuf_parse_bin(pos);
+       } else if (os_strcmp(buf, "rrm_neighbor_report") == 0) {
+               if (atoi(pos))
+                       bss->radio_measurements[0] |=
+                               WLAN_RRM_CAPS_NEIGHBOR_REPORT;
+       } else if (os_strcmp(buf, "gas_address3") == 0) {
+               bss->gas_address3 = atoi(pos);
        } else {
                wpa_printf(MSG_ERROR,
                           "Line %d: unknown configuration item '%s'",
@@ -3174,9 +3506,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 struct hostapd_config * hostapd_config_read(const char *fname)
 {
        struct hostapd_config *conf;
-       struct hostapd_bss_config *bss;
        FILE *f;
-       char buf[512], *pos;
+       char buf[4096], *pos;
        int line = 0;
        int errors = 0;
        size_t i;
@@ -3203,9 +3534,11 @@ struct hostapd_config * hostapd_config_read(const char *fname)
                return NULL;
        }
 
-       bss = conf->last_bss = conf->bss[0];
+       conf->last_bss = conf->bss[0];
 
        while (fgets(buf, sizeof(buf), f)) {
+               struct hostapd_bss_config *bss;
+
                bss = conf->last_bss;
                line++;
 
@@ -3237,7 +3570,7 @@ struct hostapd_config * hostapd_config_read(const char *fname)
        fclose(f);
 
        for (i = 0; i < conf->num_bss; i++)
-               hostapd_set_security_params(conf->bss[i]);
+               hostapd_set_security_params(conf->bss[i], 1);
 
        if (hostapd_config_check(conf, 1))
                errors++;
@@ -3256,7 +3589,8 @@ struct hostapd_config * hostapd_config_read(const char *fname)
 
 
 int hostapd_set_iface(struct hostapd_config *conf,
-                     struct hostapd_bss_config *bss, char *field, char *value)
+                     struct hostapd_bss_config *bss, const char *field,
+                     char *value)
 {
        int errors;
        size_t i;
@@ -3269,7 +3603,7 @@ int hostapd_set_iface(struct hostapd_config *conf,
        }
 
        for (i = 0; i < conf->num_bss; i++)
-               hostapd_set_security_params(conf->bss[i]);
+               hostapd_set_security_params(conf->bss[i], 0);
 
        if (hostapd_config_check(conf, 0)) {
                wpa_printf(MSG_ERROR, "Configuration check failed");