EAP peer: Add framework for external SIM/USIM processing
[mech_eap.git] / wpa_supplicant / config.c
index c3cbca6..ea7ac5a 100644 (file)
@@ -113,18 +113,6 @@ set:
 
 
 #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;
@@ -190,10 +178,17 @@ static int wpa_config_parse_int(const struct parse_data *data,
                                struct wpa_ssid *ssid,
                                int line, const char *value)
 {
-       int *dst;
+       int val, *dst;
+       char *end;
 
        dst = (int *) (((u8 *) ssid) + (long) data->param1);
-       *dst = atoi(value);
+       val = strtol(value, &end, 0);
+       if (*end) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+                          line, value);
+               return -1;
+       }
+       *dst = val;
        wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
 
        if (data->param3 && *dst < (long) data->param3) {
@@ -327,11 +322,9 @@ static int wpa_config_parse_psk(const struct parse_data *data,
                        return 0;
                ssid->psk_set = 0;
                os_free(ssid->passphrase);
-               ssid->passphrase = os_malloc(len + 1);
+               ssid->passphrase = dup_binstr(value, len);
                if (ssid->passphrase == NULL)
                        return -1;
-               os_memcpy(ssid->passphrase, value, len);
-               ssid->passphrase[len] = '\0';
                return 0;
 #else /* CONFIG_NO_PBKDF2 */
                wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
@@ -516,6 +509,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                else if (os_strcmp(start, "WPS") == 0)
                        val |= WPA_KEY_MGMT_WPS;
 #endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+               else if (os_strcmp(start, "SAE") == 0)
+                       val |= WPA_KEY_MGMT_SAE;
+               else if (os_strcmp(start, "FT-SAE") == 0)
+                       val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else {
                        wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
                                   line, start);
@@ -547,10 +546,10 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        char *buf, *pos, *end;
        int ret;
 
-       pos = buf = os_zalloc(50);
+       pos = buf = os_zalloc(100);
        if (buf == NULL)
                return NULL;
-       end = buf + 50;
+       end = buf + 100;
 
        if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
                ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
@@ -603,101 +602,8 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        }
 
 #ifdef CONFIG_IEEE80211R
-       if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
-               pos += os_snprintf(pos, end - pos, "%sFT-PSK",
-                                  pos == buf ? "" : " ");
-
-       if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
-               pos += os_snprintf(pos, end - pos, "%sFT-EAP",
-                                  pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_IEEE80211W
-       if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
-               pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
-                                  pos == buf ? "" : " ");
-
-       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
-               pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
-                                  pos == buf ? "" : " ");
-#endif /* CONFIG_IEEE80211W */
-
-#ifdef CONFIG_WPS
-       if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
-               pos += os_snprintf(pos, end - pos, "%sWPS",
-                                  pos == buf ? "" : " ");
-#endif /* CONFIG_WPS */
-
-       return buf;
-}
-#endif /* NO_CONFIG_WRITE */
-
-
-static int wpa_config_parse_cipher(int line, const char *value)
-{
-       int val = 0, last;
-       char *start, *end, *buf;
-
-       buf = os_strdup(value);
-       if (buf == NULL)
-               return -1;
-       start = buf;
-
-       while (*start != '\0') {
-               while (*start == ' ' || *start == '\t')
-                       start++;
-               if (*start == '\0')
-                       break;
-               end = start;
-               while (*end != ' ' && *end != '\t' && *end != '\0')
-                       end++;
-               last = *end == '\0';
-               *end = '\0';
-               if (os_strcmp(start, "CCMP") == 0)
-                       val |= WPA_CIPHER_CCMP;
-               else if (os_strcmp(start, "TKIP") == 0)
-                       val |= WPA_CIPHER_TKIP;
-               else if (os_strcmp(start, "WEP104") == 0)
-                       val |= WPA_CIPHER_WEP104;
-               else if (os_strcmp(start, "WEP40") == 0)
-                       val |= WPA_CIPHER_WEP40;
-               else if (os_strcmp(start, "NONE") == 0)
-                       val |= WPA_CIPHER_NONE;
-               else {
-                       wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
-                                  line, start);
-                       os_free(buf);
-                       return -1;
-               }
-
-               if (last)
-                       break;
-               start = end + 1;
-       }
-       os_free(buf);
-
-       if (val == 0) {
-               wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
-                          line);
-               return -1;
-       }
-       return val;
-}
-
-
-#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_cipher(int cipher)
-{
-       char *buf, *pos, *end;
-       int ret;
-
-       pos = buf = os_zalloc(50);
-       if (buf == NULL)
-               return NULL;
-       end = buf + 50;
-
-       if (cipher & WPA_CIPHER_CCMP) {
-               ret = os_snprintf(pos, end - pos, "%sCCMP",
+       if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+               ret = os_snprintf(pos, end - pos, "%sFT-PSK",
                                  pos == buf ? "" : " ");
                if (ret < 0 || ret >= end - pos) {
                        end[-1] = '\0';
@@ -706,8 +612,8 @@ static char * wpa_config_write_cipher(int cipher)
                pos += ret;
        }
 
-       if (cipher & WPA_CIPHER_TKIP) {
-               ret = os_snprintf(pos, end - pos, "%sTKIP",
+       if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+               ret = os_snprintf(pos, end - pos, "%sFT-EAP",
                                  pos == buf ? "" : " ");
                if (ret < 0 || ret >= end - pos) {
                        end[-1] = '\0';
@@ -715,9 +621,11 @@ static char * wpa_config_write_cipher(int cipher)
                }
                pos += ret;
        }
+#endif /* CONFIG_IEEE80211R */
 
-       if (cipher & WPA_CIPHER_WEP104) {
-               ret = os_snprintf(pos, end - pos, "%sWEP104",
+#ifdef CONFIG_IEEE80211W
+       if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+               ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
                                  pos == buf ? "" : " ");
                if (ret < 0 || ret >= end - pos) {
                        end[-1] = '\0';
@@ -726,8 +634,8 @@ static char * wpa_config_write_cipher(int cipher)
                pos += ret;
        }
 
-       if (cipher & WPA_CIPHER_WEP40) {
-               ret = os_snprintf(pos, end - pos, "%sWEP40",
+       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+               ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
                                  pos == buf ? "" : " ");
                if (ret < 0 || ret >= end - pos) {
                        end[-1] = '\0';
@@ -735,9 +643,11 @@ static char * wpa_config_write_cipher(int cipher)
                }
                pos += ret;
        }
+#endif /* CONFIG_IEEE80211W */
 
-       if (cipher & WPA_CIPHER_NONE) {
-               ret = os_snprintf(pos, end - pos, "%sNONE",
+#ifdef CONFIG_WPS
+       if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+               ret = os_snprintf(pos, end - pos, "%sWPS",
                                  pos == buf ? "" : " ");
                if (ret < 0 || ret >= end - pos) {
                        end[-1] = '\0';
@@ -745,6 +655,41 @@ static char * wpa_config_write_cipher(int cipher)
                }
                pos += ret;
        }
+#endif /* CONFIG_WPS */
+
+       return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+       int val = wpa_parse_cipher(value);
+       if (val < 0) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+                          line, value);
+               return -1;
+       }
+       if (val == 0) {
+               wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+                          line);
+               return -1;
+       }
+       return val;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_cipher(int cipher)
+{
+       char *buf = os_zalloc(50);
+       if (buf == NULL)
+               return NULL;
+
+       if (wpa_write_ciphers(buf, buf + 50, cipher, " ") < 0) {
+               os_free(buf);
+               return NULL;
+       }
 
        return buf;
 }
@@ -759,7 +704,7 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
        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_ALLOWED_PAIRWISE_CIPHERS) {
                wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
                           "(0x%x).", line, val);
                return -1;
@@ -788,8 +733,7 @@ static int wpa_config_parse_group(const struct parse_data *data,
        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_ALLOWED_GROUP_CIPHERS) {
                wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
                           "(0x%x).", line, val);
                return -1;
@@ -909,9 +853,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
 #endif /* NO_CONFIG_WRITE */
 
 
-static int * wpa_config_parse_freqs(const struct parse_data *data,
-                                   struct wpa_ssid *ssid, int line,
-                                   const char *value)
+static int * wpa_config_parse_int_array(const char *value)
 {
        int *freqs;
        size_t used, len;
@@ -919,7 +861,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
 
        used = 0;
        len = 10;
-       freqs = os_zalloc((len + 1) * sizeof(int));
+       freqs = os_calloc(len + 1, sizeof(int));
        if (freqs == NULL)
                return NULL;
 
@@ -930,7 +872,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data,
                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;
@@ -958,9 +900,13 @@ static int wpa_config_parse_scan_freq(const struct parse_data *data,
 {
        int *freqs;
 
-       freqs = wpa_config_parse_freqs(data, ssid, line, value);
+       freqs = wpa_config_parse_int_array(value);
        if (freqs == NULL)
                return -1;
+       if (freqs[0] == 0) {
+               os_free(freqs);
+               freqs = NULL;
+       }
        os_free(ssid->scan_freq);
        ssid->scan_freq = freqs;
 
@@ -974,9 +920,13 @@ static int wpa_config_parse_freq_list(const struct parse_data *data,
 {
        int *freqs;
 
-       freqs = wpa_config_parse_freqs(data, ssid, line, value);
+       freqs = wpa_config_parse_int_array(value);
        if (freqs == NULL)
                return -1;
+       if (freqs[0] == 0) {
+               os_free(freqs);
+               freqs = NULL;
+       }
        os_free(ssid->freq_list);
        ssid->freq_list = freqs;
 
@@ -1059,8 +1009,8 @@ static int wpa_config_parse_eap(const struct parse_data *data,
                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);
@@ -1090,7 +1040,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
        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;
@@ -1388,18 +1338,27 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
                        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);
@@ -1433,10 +1392,10 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
        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;
@@ -1451,6 +1410,60 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
 }
 #endif /* NO_CONFIG_WRITE */
 
+
+static int wpa_config_parse_psk_list(const struct parse_data *data,
+                                    struct wpa_ssid *ssid, int line,
+                                    const char *value)
+{
+       struct psk_list_entry *p;
+       const char *pos;
+
+       p = os_zalloc(sizeof(*p));
+       if (p == NULL)
+               return -1;
+
+       pos = value;
+       if (os_strncmp(pos, "P2P-", 4) == 0) {
+               p->p2p = 1;
+               pos += 4;
+       }
+
+       if (hwaddr_aton(pos, p->addr)) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list address '%s'",
+                          line, pos);
+               os_free(p);
+               return -1;
+       }
+       pos += 17;
+       if (*pos != '-') {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list '%s'",
+                          line, pos);
+               os_free(p);
+               return -1;
+       }
+       pos++;
+
+       if (hexstr2bin(pos, p->psk, PMK_LEN) || pos[PMK_LEN * 2] != '\0') {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid psk_list PSK '%s'",
+                          line, pos);
+               os_free(p);
+               return -1;
+       }
+
+       dl_list_add(&ssid->psk_list, &p->list);
+
+       return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_psk_list(const struct parse_data *data,
+                                       struct wpa_ssid *ssid)
+{
+       return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
 #endif /* CONFIG_P2P */
 
 /* Helper macros for network block parser */
@@ -1566,6 +1579,7 @@ static const struct parse_data ssid_fields[] = {
        { STRe(dh_file) },
        { STRe(subject_match) },
        { STRe(altsubject_match) },
+       { STRe(domain_suffix_match) },
        { STRe(ca_cert2) },
        { STRe(ca_path2) },
        { STRe(client_cert2) },
@@ -1574,6 +1588,7 @@ static const struct parse_data ssid_fields[] = {
        { STRe(dh_file2) },
        { STRe(subject_match2) },
        { STRe(altsubject_match2) },
+       { STRe(domain_suffix_match2) },
        { STRe(phase1) },
        { STRe(phase2) },
        { STRe(pcsc) },
@@ -1601,6 +1616,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(eap_workaround) },
        { STRe(pac_file) },
        { INTe(fragment_size) },
+       { INTe(ocsp) },
 #endif /* IEEE8021X_EAPOL */
        { INT_RANGE(mode, 0, 4) },
        { INT_RANGE(proactive_key_caching, 0, 1) },
@@ -1611,23 +1627,47 @@ static const struct parse_data ssid_fields[] = {
 #endif /* CONFIG_IEEE80211W */
        { INT_RANGE(peerkey, 0, 1) },
        { INT_RANGE(mixed_cell, 0, 1) },
-       { INT_RANGE(frequency, 0, 10000) },
+       { INT_RANGE(frequency, 0, 65000) },
        { INT(wpa_ptk_rekey) },
        { STR(bgscan) },
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
        { FUNC(p2p_client_list) },
+       { FUNC(psk_list) },
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_HT_OVERRIDES
        { INT_RANGE(disable_ht, 0, 1) },
        { INT_RANGE(disable_ht40, -1, 1) },
+       { INT_RANGE(disable_sgi, 0, 1) },
        { INT_RANGE(disable_max_amsdu, -1, 1) },
        { INT_RANGE(ampdu_factor, -1, 3) },
        { INT_RANGE(ampdu_density, -1, 7) },
        { STR(ht_mcs) },
 #endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+       { INT_RANGE(disable_vht, 0, 1) },
+       { INT(vht_capa) },
+       { INT(vht_capa_mask) },
+       { INT_RANGE(vht_rx_mcs_nss_1, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_2, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_3, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_4, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_5, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_6, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_7, -1, 3) },
+       { INT_RANGE(vht_rx_mcs_nss_8, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_1, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_2, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_3, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_4, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_5, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_6, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_7, -1, 3) },
+       { INT_RANGE(vht_tx_mcs_nss_8, -1, 3) },
+#endif /* CONFIG_VHT_OVERRIDES */
        { INT(ap_max_inactivity) },
        { INT(dtim_period) },
+       { INT(beacon_int) },
 };
 
 #undef OFFSET
@@ -1681,8 +1721,8 @@ int wpa_config_add_prio_network(struct wpa_config *config,
        }
 
        /* 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;
 
@@ -1748,6 +1788,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        os_free(eap->dh_file);
        os_free(eap->subject_match);
        os_free(eap->altsubject_match);
+       os_free(eap->domain_suffix_match);
        os_free(eap->ca_cert2);
        os_free(eap->ca_path2);
        os_free(eap->client_cert2);
@@ -1756,6 +1797,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        os_free(eap->dh_file2);
        os_free(eap->subject_match2);
        os_free(eap->altsubject_match2);
+       os_free(eap->domain_suffix_match2);
        os_free(eap->phase1);
        os_free(eap->phase2);
        os_free(eap->pcsc);
@@ -1773,6 +1815,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        os_free(eap->pending_req_otp);
        os_free(eap->pac_file);
        os_free(eap->new_password);
+       os_free(eap->external_sim_resp);
 }
 #endif /* IEEE8021X_EAPOL */
 
@@ -1786,6 +1829,8 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
  */
 void wpa_config_free_ssid(struct wpa_ssid *ssid)
 {
+       struct psk_list_entry *psk;
+
        os_free(ssid->ssid);
        os_free(ssid->passphrase);
        os_free(ssid->ext_psk);
@@ -1800,12 +1845,19 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
 #ifdef CONFIG_HT_OVERRIDES
        os_free(ssid->ht_mcs);
 #endif /* CONFIG_HT_OVERRIDES */
+       while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
+                                   list))) {
+               dl_list_del(&psk->list);
+               os_free(psk);
+       }
        os_free(ssid);
 }
 
 
 void wpa_config_free_cred(struct wpa_cred *cred)
 {
+       size_t i;
+
        os_free(cred->realm);
        os_free(cred->username);
        os_free(cred->password);
@@ -1815,10 +1867,14 @@ void wpa_config_free_cred(struct wpa_cred *cred)
        os_free(cred->private_key_passwd);
        os_free(cred->imsi);
        os_free(cred->milenage);
+       for (i = 0; i < cred->num_domain; i++)
+               os_free(cred->domain[i]);
        os_free(cred->domain);
+       os_free(cred->domain_suffix_match);
        os_free(cred->eap_method);
        os_free(cred->phase1);
        os_free(cred->phase2);
+       os_free(cred->excluded_ssid);
        os_free(cred);
 }
 
@@ -1881,10 +1937,13 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->pssid);
        os_free(config->p2p_pref_chan);
        os_free(config->autoscan);
+       os_free(config->freq_list);
        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->sae_groups);
+       wpabuf_free(config->ap_vendor_elements);
        os_free(config);
 }
 
@@ -1959,6 +2018,7 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
        if (ssid == NULL)
                return NULL;
        ssid->id = id;
+       dl_list_init(&ssid->psk_list);
        if (last)
                last->next = ssid;
        else
@@ -2021,10 +2081,33 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
 #ifdef CONFIG_HT_OVERRIDES
        ssid->disable_ht = DEFAULT_DISABLE_HT;
        ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
+       ssid->disable_sgi = DEFAULT_DISABLE_SGI;
        ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
        ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
        ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
 #endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_VHT_OVERRIDES
+       ssid->vht_rx_mcs_nss_1 = -1;
+       ssid->vht_rx_mcs_nss_2 = -1;
+       ssid->vht_rx_mcs_nss_3 = -1;
+       ssid->vht_rx_mcs_nss_4 = -1;
+       ssid->vht_rx_mcs_nss_5 = -1;
+       ssid->vht_rx_mcs_nss_6 = -1;
+       ssid->vht_rx_mcs_nss_7 = -1;
+       ssid->vht_rx_mcs_nss_8 = -1;
+       ssid->vht_tx_mcs_nss_1 = -1;
+       ssid->vht_tx_mcs_nss_2 = -1;
+       ssid->vht_tx_mcs_nss_3 = -1;
+       ssid->vht_tx_mcs_nss_4 = -1;
+       ssid->vht_tx_mcs_nss_5 = -1;
+       ssid->vht_tx_mcs_nss_6 = -1;
+       ssid->vht_tx_mcs_nss_7 = -1;
+       ssid->vht_tx_mcs_nss_8 = -1;
+#endif /* CONFIG_VHT_OVERRIDES */
+       ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+       ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -2119,7 +2202,7 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
 
        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;
 
@@ -2359,9 +2442,23 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
                return 0;
        }
 
+       if (os_strcmp(var, "domain_suffix_match") == 0) {
+               os_free(cred->domain_suffix_match);
+               cred->domain_suffix_match = val;
+               return 0;
+       }
+
        if (os_strcmp(var, "domain") == 0) {
-               os_free(cred->domain);
-               cred->domain = val;
+               char **new_domain;
+               new_domain = os_realloc_array(cred->domain,
+                                             cred->num_domain + 1,
+                                             sizeof(char *));
+               if (new_domain == NULL) {
+                       os_free(val);
+                       return -1;
+               }
+               new_domain[cred->num_domain++] = val;
+               cred->domain = new_domain;
                return 0;
        }
 
@@ -2391,6 +2488,49 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
                return 0;
        }
 
+       if (os_strcmp(var, "required_roaming_consortium") == 0) {
+               if (len < 3 || len > sizeof(cred->required_roaming_consortium))
+               {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                  "required_roaming_consortium length %d "
+                                  "(3..15 expected)", line, (int) len);
+                       os_free(val);
+                       return -1;
+               }
+               os_memcpy(cred->required_roaming_consortium, val, len);
+               cred->required_roaming_consortium_len = len;
+               os_free(val);
+               return 0;
+       }
+
+       if (os_strcmp(var, "excluded_ssid") == 0) {
+               struct excluded_ssid *e;
+
+               if (len > MAX_SSID_LEN) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                  "excluded_ssid length %d", line, (int) len);
+                       os_free(val);
+                       return -1;
+               }
+
+               e = os_realloc_array(cred->excluded_ssid,
+                                    cred->num_excluded_ssid + 1,
+                                    sizeof(struct excluded_ssid));
+               if (e == NULL) {
+                       os_free(val);
+                       return -1;
+               }
+               cred->excluded_ssid = e;
+
+               e = &cred->excluded_ssid[cred->num_excluded_ssid++];
+               os_memcpy(e->ssid, val, len);
+               e->ssid_len = len;
+
+               os_free(val);
+
+               return 0;
+       }
+
        if (line) {
                wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
                           line, var);
@@ -2561,6 +2701,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
                                           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)
@@ -2570,11 +2719,17 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        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->scan_cur_freq = DEFAULT_SCAN_CUR_FREQ;
+       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);
@@ -2623,9 +2778,18 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
                                       struct wpa_config *config, int line,
                                       const char *pos)
 {
-       int *dst;
+       int val, *dst;
+       char *end;
+
        dst = (int *) (((u8 *) config) + (long) data->param1);
-       *dst = atoi(pos);
+       val = strtol(pos, &end, 0);
+       if (*end) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid number \"%s\"",
+                          line, pos);
+               return -1;
+       }
+       *dst = val;
+
        wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
 
        if (data->param2 && *dst < (long) data->param2) {
@@ -2712,6 +2876,25 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
 }
 
 
+static int wpa_config_process_freq_list(const struct global_parse_data *data,
+                                       struct wpa_config *config, int line,
+                                       const char *value)
+{
+       int *freqs;
+
+       freqs = wpa_config_parse_int_array(value);
+       if (freqs == NULL)
+               return -1;
+       if (freqs[0] == 0) {
+               os_free(freqs);
+               freqs = NULL;
+       }
+       os_free(config->freq_list);
+       config->freq_list = freqs;
+       return 0;
+}
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
                                      struct wpa_config *config, int line,
                                      const char *pos)
@@ -2867,7 +3050,8 @@ static int wpa_config_process_p2p_pref_chan(
                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;
@@ -2912,6 +3096,74 @@ static int wpa_config_process_hessid(
 }
 
 
+static int wpa_config_process_sae_groups(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       int *groups = wpa_config_parse_int_array(pos);
+       if (groups == NULL) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid sae_groups '%s'",
+                          line, pos);
+               return -1;
+       }
+
+       os_free(config->sae_groups);
+       config->sae_groups = groups;
+
+       return 0;
+}
+
+
+static int wpa_config_process_ap_vendor_elements(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       struct wpabuf *tmp;
+       int len = os_strlen(pos) / 2;
+       u8 *p;
+
+       if (!len) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid ap_vendor_elements",
+                          line);
+               return -1;
+       }
+
+       tmp = wpabuf_alloc(len);
+       if (tmp) {
+               p = wpabuf_put(tmp, len);
+
+               if (hexstr2bin(pos, p, len)) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                  "ap_vendor_elements", line);
+                       wpabuf_free(tmp);
+                       return -1;
+               }
+
+               wpabuf_free(config->ap_vendor_elements);
+               config->ap_vendor_elements = tmp;
+       } else {
+               wpa_printf(MSG_ERROR, "Cannot allocate memory for "
+                          "ap_vendor_elements");
+               return -1;
+       }
+
+       return 0;
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static int wpa_config_process_no_ctrl_interface(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       wpa_printf(MSG_DEBUG, "no_ctrl_interface -> ctrl_interface=NULL");
+       os_free(config->ctrl_interface);
+       config->ctrl_interface = NULL;
+       return 0;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -2931,6 +3183,7 @@ static int wpa_config_process_hessid(
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
        { STR(ctrl_interface), 0 },
+       { FUNC_NO_VAR(no_ctrl_interface), 0 },
        { STR(ctrl_interface_group), 0 } /* deprecated */,
 #endif /* CONFIG_CTRL_IFACE */
        { INT_RANGE(eapol_version, 1, 2), 0 },
@@ -2942,6 +3195,7 @@ static const struct global_parse_data global_fields[] = {
        { STR(pkcs11_module_path), 0 },
        { STR(pcsc_reader), 0 },
        { STR(pcsc_pin), 0 },
+       { INT(external_sim), 0 },
        { STR(driver_param), 0 },
        { INT(dot11RSNAConfigPMKLifetime), 0 },
        { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
@@ -2967,14 +3221,18 @@ static const struct global_parse_data global_fields[] = {
        { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
        { INT(p2p_listen_reg_class), 0 },
        { INT(p2p_listen_channel), 0 },
-       { INT(p2p_oper_reg_class), 0 },
-       { INT(p2p_oper_channel), 0 },
+       { INT(p2p_oper_reg_class), CFG_CHANGED_P2P_OPER_CHANNEL },
+       { INT(p2p_oper_channel), CFG_CHANGED_P2P_OPER_CHANNEL },
        { INT_RANGE(p2p_go_intent, 0, 15), 0 },
        { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
        { INT_RANGE(persistent_reconnect, 0, 1), 0 },
        { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
        { INT(p2p_group_idle), 0 },
        { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+       { INT(p2p_go_ht40), 0 },
+       { INT(p2p_disabled), 0 },
+       { INT(p2p_no_group_iface), 0 },
+       { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
 #endif /* CONFIG_P2P */
        { FUNC(country), CFG_CHANGED_COUNTRY },
        { INT(bss_max_count), 0 },
@@ -2992,11 +3250,24 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(access_network_type, 0, 15), 0 },
        { INT_RANGE(pbc_in_m1, 0, 1), 0 },
        { STR(autoscan), 0 },
-       { 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 },
-       { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }
+       { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff),
+         CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { BIN(wps_nfc_dh_pubkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { BIN(wps_nfc_dh_privkey), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { BIN(wps_nfc_dev_pw), CFG_CHANGED_NFC_PASSWORD_TOKEN },
+       { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+       { INT(p2p_go_max_inactivity), 0 },
+       { INT_RANGE(auto_interworking, 0, 1), 0 },
+       { INT(okc), 0 },
+       { INT(pmf), 0 },
+       { FUNC(sae_groups), 0 },
+       { INT(dtim_period), 0 },
+       { INT(beacon_int), 0 },
+       { FUNC(ap_vendor_elements), 0 },
+       { INT_RANGE(ignore_old_scan_res, 0, 1), 0 },
+       { FUNC(freq_list), 0 },
+       { INT(scan_cur_freq), 0 },
+       { INT(sched_scan_interval), 0 },
 };
 
 #undef FUNC
@@ -3027,10 +3298,31 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
                                   "parse '%s'.", line, pos);
                        ret = -1;
                }
+               if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
+                       config->wps_nfc_pw_from_config = 1;
                config->changed_parameters |= field->changed_flag;
                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'.",