TDLS: Declare tdls_testing as extern in a header file
[mech_eap.git] / wpa_supplicant / config.c
index 45a346a..0571c23 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2012, 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.
@@ -15,6 +15,7 @@
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
 #include "p2p/p2p.h"
+#include "fst/fst.h"
 #include "config.h"
 
 
@@ -31,7 +32,11 @@ struct parse_data {
        /* Configuration variable name */
        char *name;
 
-       /* Parser function for this variable */
+       /* Parser function for this variable. The parser functions return 0 or 1
+        * to indicate success. Value 0 indicates that the parameter value may
+        * have changed while value 1 means that the value did not change.
+        * Error cases (failure to parse the string) are indicated by returning
+        * -1. */
        int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
                      int line, const char *value);
 
@@ -58,7 +63,7 @@ static int wpa_config_parse_str(const struct parse_data *data,
                                struct wpa_ssid *ssid,
                                int line, const char *value)
 {
-       size_t res_len, *dst_len;
+       size_t res_len, *dst_len, prev_len;
        char **dst, *tmp;
 
        if (os_strcmp(value, "NULL") == 0) {
@@ -104,6 +109,21 @@ static int wpa_config_parse_str(const struct parse_data *data,
 set:
        dst = (char **) (((u8 *) ssid) + (long) data->param1);
        dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+       if (data->param2)
+               prev_len = *dst_len;
+       else if (*dst)
+               prev_len = os_strlen(*dst);
+       else
+               prev_len = 0;
+       if ((*dst == NULL && tmp == NULL) ||
+           (*dst && tmp && prev_len == res_len &&
+            os_memcmp(*dst, tmp, res_len) == 0)) {
+               /* No change to the previously configured value */
+               os_free(tmp);
+               return 1;
+       }
+
        os_free(*dst);
        *dst = tmp;
        if (data->param2)
@@ -189,6 +209,9 @@ static int wpa_config_parse_int(const struct parse_data *data,
                           line, value);
                return -1;
        }
+
+       if (*dst == val)
+               return 1;
        *dst = val;
        wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
 
@@ -225,7 +248,7 @@ static char * wpa_config_write_int(const struct parse_data *data,
        if (value == NULL)
                return NULL;
        res = os_snprintf(value, 20, "%d", *src);
-       if (res < 0 || res >= 20) {
+       if (os_snprintf_error(20, res)) {
                os_free(value);
                return NULL;
        }
@@ -235,6 +258,99 @@ static char * wpa_config_write_int(const struct parse_data *data,
 #endif /* NO_CONFIG_WRITE */
 
 
+static int wpa_config_parse_addr_list(const struct parse_data *data,
+                                     int line, const char *value,
+                                     u8 **list, size_t *num, char *name,
+                                     u8 abort_on_error, u8 masked)
+{
+       const char *pos;
+       u8 *buf, *n, addr[2 * ETH_ALEN];
+       size_t count;
+
+       buf = NULL;
+       count = 0;
+
+       pos = value;
+       while (pos && *pos) {
+               while (*pos == ' ')
+                       pos++;
+
+               if (hwaddr_masked_aton(pos, addr, &addr[ETH_ALEN], masked)) {
+                       if (abort_on_error || count == 0) {
+                               wpa_printf(MSG_ERROR,
+                                          "Line %d: Invalid %s address '%s'",
+                                          line, name, 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 %s address '%s'",
+                                  line, name, pos);
+               } else {
+                       n = os_realloc_array(buf, count + 1, 2 * ETH_ALEN);
+                       if (n == NULL) {
+                               os_free(buf);
+                               return -1;
+                       }
+                       buf = n;
+                       os_memmove(buf + 2 * ETH_ALEN, buf,
+                                  count * 2 * ETH_ALEN);
+                       os_memcpy(buf, addr, 2 * ETH_ALEN);
+                       count++;
+                       wpa_printf(MSG_MSGDUMP,
+                                  "%s: addr=" MACSTR " mask=" MACSTR,
+                                  name, MAC2STR(addr),
+                                  MAC2STR(&addr[ETH_ALEN]));
+               }
+
+               pos = os_strchr(pos, ' ');
+       }
+
+       os_free(*list);
+       *list = buf;
+       *num = count;
+
+       return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_addr_list(const struct parse_data *data,
+                                        const u8 *list, size_t num, char *name)
+{
+       char *value, *end, *pos;
+       int res;
+       size_t i;
+
+       if (list == NULL || num == 0)
+               return NULL;
+
+       value = os_malloc(2 * 20 * num);
+       if (value == NULL)
+               return NULL;
+       pos = value;
+       end = value + 2 * 20 * num;
+
+       for (i = num; i > 0; i--) {
+               const u8 *a = list + (i - 1) * 2 * ETH_ALEN;
+               const u8 *m = a + ETH_ALEN;
+
+               if (i < num)
+                       *pos++ = ' ';
+               res = hwaddr_mask_txt(pos, end - pos, a, m);
+               if (res < 0) {
+                       os_free(value);
+                       return NULL;
+               }
+               pos += res;
+       }
+
+       return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
 static int wpa_config_parse_bssid(const struct parse_data *data,
                                  struct wpa_ssid *ssid, int line,
                                  const char *value)
@@ -270,7 +386,7 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
        if (value == NULL)
                return NULL;
        res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
-       if (res < 0 || res >= 20) {
+       if (os_snprintf_error(20, res)) {
                os_free(value);
                return NULL;
        }
@@ -280,6 +396,50 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
 #endif /* NO_CONFIG_WRITE */
 
 
+static int wpa_config_parse_bssid_blacklist(const struct parse_data *data,
+                                           struct wpa_ssid *ssid, int line,
+                                           const char *value)
+{
+       return wpa_config_parse_addr_list(data, line, value,
+                                         &ssid->bssid_blacklist,
+                                         &ssid->num_bssid_blacklist,
+                                         "bssid_blacklist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_blacklist(const struct parse_data *data,
+                                              struct wpa_ssid *ssid)
+{
+       return wpa_config_write_addr_list(data, ssid->bssid_blacklist,
+                                         ssid->num_bssid_blacklist,
+                                         "bssid_blacklist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_bssid_whitelist(const struct parse_data *data,
+                                           struct wpa_ssid *ssid, int line,
+                                           const char *value)
+{
+       return wpa_config_parse_addr_list(data, line, value,
+                                         &ssid->bssid_whitelist,
+                                         &ssid->num_bssid_whitelist,
+                                         "bssid_whitelist", 1, 1);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid_whitelist(const struct parse_data *data,
+                                              struct wpa_ssid *ssid)
+{
+       return wpa_config_write_addr_list(data, ssid->bssid_whitelist,
+                                         ssid->num_bssid_whitelist,
+                                         "bssid_whitelist");
+}
+#endif /* NO_CONFIG_WRITE */
+
+
 static int wpa_config_parse_psk(const struct parse_data *data,
                                struct wpa_ssid *ssid, int line,
                                const char *value)
@@ -318,9 +478,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
                }
                wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
                                      (u8 *) value, len);
+               if (has_ctrl_char((u8 *) value, len)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Invalid passphrase character",
+                                  line);
+                       return -1;
+               }
                if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
-                   os_memcmp(ssid->passphrase, value, len) == 0)
-                       return 0;
+                   os_memcmp(ssid->passphrase, value, len) == 0) {
+                       /* No change to the previously configured value */
+                       return 1;
+               }
                ssid->psk_set = 0;
                str_clear_free(ssid->passphrase);
                ssid->passphrase = dup_binstr(value, len);
@@ -358,9 +526,15 @@ static char * wpa_config_write_psk(const struct parse_data *data,
        if (ssid->ext_psk) {
                size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
                char *buf = os_malloc(len);
+               int res;
+
                if (buf == NULL)
                        return NULL;
-               os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+               res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+               if (os_snprintf_error(len, res)) {
+                       os_free(buf);
+                       buf = NULL;
+               }
                return buf;
        }
 #endif /* CONFIG_EXT_PASSWORD */
@@ -425,6 +599,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->proto == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
        ssid->proto = val;
        return errors ? -1 : 0;
@@ -446,7 +622,7 @@ static char * wpa_config_write_proto(const struct parse_data *data,
        if (ssid->proto & WPA_PROTO_WPA) {
                ret = os_snprintf(pos, end - pos, "%sWPA",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos)
+               if (os_snprintf_error(end - pos, ret))
                        return buf;
                pos += ret;
        }
@@ -454,7 +630,7 @@ static char * wpa_config_write_proto(const struct parse_data *data,
        if (ssid->proto & WPA_PROTO_RSN) {
                ret = os_snprintf(pos, end - pos, "%sRSN",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos)
+               if (os_snprintf_error(end - pos, ret))
                        return buf;
                pos += ret;
        }
@@ -462,7 +638,7 @@ static char * wpa_config_write_proto(const struct parse_data *data,
        if (ssid->proto & WPA_PROTO_OSEN) {
                ret = os_snprintf(pos, end - pos, "%sOSEN",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos)
+               if (os_snprintf_error(end - pos, ret))
                        return buf;
                pos += ret;
        }
@@ -535,6 +711,14 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                else if (os_strcmp(start, "OSEN") == 0)
                        val |= WPA_KEY_MGMT_OSEN;
 #endif /* CONFIG_HS20 */
+#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);
@@ -553,6 +737,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->key_mgmt == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
        ssid->key_mgmt = val;
        return errors ? -1 : 0;
@@ -574,7 +760,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
                ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -584,7 +770,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
                ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -594,7 +780,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
                ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -604,7 +790,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
                ret = os_snprintf(pos, end - pos, "%sNONE",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -614,7 +800,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
                ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -625,7 +811,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        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) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -635,7 +821,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        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) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -647,7 +833,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        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) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -657,7 +843,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        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) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -669,7 +855,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
                ret = os_snprintf(pos, end - pos, "%sWPS",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -681,7 +867,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
                ret = os_snprintf(pos, end - pos, "%sSAE",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -691,7 +877,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
                ret = os_snprintf(pos, end - pos, "%sFT-SAE",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -703,7 +889,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
                ret = os_snprintf(pos, end - pos, "%sOSEN",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -711,6 +897,30 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
        }
 #endif /* CONFIG_HS20 */
 
+#ifdef CONFIG_SUITEB
+       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+               ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
+                                 pos == buf ? "" : " ");
+               if (os_snprintf_error(end - pos, ret)) {
+                       end[-1] = '\0';
+                       return buf;
+               }
+               pos += ret;
+       }
+#endif /* CONFIG_SUITEB */
+
+#ifdef CONFIG_SUITEB192
+       if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+               ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192",
+                                 pos == buf ? "" : " ");
+               if (os_snprintf_error(end - pos, ret)) {
+                       end[-1] = '\0';
+                       return buf;
+               }
+               pos += ret;
+       }
+#endif /* CONFIG_SUITEB192 */
+
        if (pos == buf) {
                os_free(buf);
                buf = NULL;
@@ -723,6 +933,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
 
 static int wpa_config_parse_cipher(int line, const char *value)
 {
+#ifdef CONFIG_NO_WPA
+       return -1;
+#else /* CONFIG_NO_WPA */
        int val = wpa_parse_cipher(value);
        if (val < 0) {
                wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
@@ -735,12 +948,16 @@ static int wpa_config_parse_cipher(int line, const char *value)
                return -1;
        }
        return val;
+#endif /* CONFIG_NO_WPA */
 }
 
 
 #ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_cipher(int cipher)
 {
+#ifdef CONFIG_NO_WPA
+       return NULL;
+#else /* CONFIG_NO_WPA */
        char *buf = os_zalloc(50);
        if (buf == NULL)
                return NULL;
@@ -751,6 +968,7 @@ static char * wpa_config_write_cipher(int cipher)
        }
 
        return buf;
+#endif /* CONFIG_NO_WPA */
 }
 #endif /* NO_CONFIG_WRITE */
 
@@ -769,6 +987,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
                return -1;
        }
 
+       if (ssid->pairwise_cipher == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
        ssid->pairwise_cipher = val;
        return 0;
@@ -792,12 +1012,21 @@ static int wpa_config_parse_group(const struct parse_data *data,
        val = wpa_config_parse_cipher(line, value);
        if (val == -1)
                return -1;
+
+       /*
+        * Backwards compatibility - filter out WEP ciphers that were previously
+        * allowed.
+        */
+       val &= ~(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;
        }
 
+       if (ssid->group_cipher == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
        ssid->group_cipher = val;
        return 0;
@@ -859,6 +1088,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->auth_alg == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
        ssid->auth_alg = val;
        return errors ? -1 : 0;
@@ -880,7 +1111,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
        if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
                ret = os_snprintf(pos, end - pos, "%sOPEN",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -890,7 +1121,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
        if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
                ret = os_snprintf(pos, end - pos, "%sSHARED",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -900,7 +1131,7 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
        if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
                ret = os_snprintf(pos, end - pos, "%sLEAP",
                                  pos == buf ? "" : " ");
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -1021,7 +1252,7 @@ static char * wpa_config_write_freqs(const struct parse_data *data,
        for (i = 0; freqs[i]; i++) {
                ret = os_snprintf(pos, end - pos, "%s%u",
                                  i == 0 ? "" : " ", freqs[i]);
-               if (ret < 0 || ret >= end - pos) {
+               if (os_snprintf_error(end - pos, ret)) {
                        end[-1] = '\0';
                        return buf;
                }
@@ -1113,6 +1344,32 @@ static int wpa_config_parse_eap(const struct parse_data *data,
        methods[num_methods].method = EAP_TYPE_NONE;
        num_methods++;
 
+       if (!errors && ssid->eap.eap_methods) {
+               struct eap_method_type *prev_m;
+               size_t i, j, prev_methods, match = 0;
+
+               prev_m = ssid->eap.eap_methods;
+               for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+                            prev_m[i].method != EAP_TYPE_NONE; i++) {
+                       /* Count the methods */
+               }
+               prev_methods = i + 1;
+
+               for (i = 0; prev_methods == num_methods && i < prev_methods;
+                    i++) {
+                       for (j = 0; j < num_methods; j++) {
+                               if (prev_m[i].vendor == methods[j].vendor &&
+                                   prev_m[i].method == methods[j].method) {
+                                       match++;
+                                       break;
+                               }
+                       }
+               }
+               if (match == num_methods) {
+                       os_free(methods);
+                       return 1;
+               }
+       }
        wpa_hexdump(MSG_MSGDUMP, "eap methods",
                    (u8 *) methods, num_methods * sizeof(*methods));
        os_free(ssid->eap.eap_methods);
@@ -1121,6 +1378,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
 }
 
 
+#ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_eap(const struct parse_data *data,
                                   struct wpa_ssid *ssid)
 {
@@ -1144,7 +1402,7 @@ static char * wpa_config_write_eap(const struct parse_data *data,
                if (name) {
                        ret = os_snprintf(pos, end - pos, "%s%s",
                                          pos == buf ? "" : " ", name);
-                       if (ret < 0 || ret >= end - pos)
+                       if (os_snprintf_error(end - pos, ret))
                                break;
                        pos += ret;
                }
@@ -1154,6 +1412,7 @@ static char * wpa_config_write_eap(const struct parse_data *data,
 
        return buf;
 }
+#endif /* NO_CONFIG_WRITE */
 
 
 static int wpa_config_parse_password(const struct parse_data *data,
@@ -1163,6 +1422,8 @@ static int wpa_config_parse_password(const struct parse_data *data,
        u8 *hash;
 
        if (os_strcmp(value, "NULL") == 0) {
+               if (!ssid->eap.password)
+                       return 1; /* Already unset */
                wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
                bin_clear_free(ssid->eap.password, ssid->eap.password_len);
                ssid->eap.password = NULL;
@@ -1226,6 +1487,12 @@ static int wpa_config_parse_password(const struct parse_data *data,
 
        wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
 
+       if (ssid->eap.password && ssid->eap.password_len == 16 &&
+           os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+           (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+               bin_clear_free(hash, 16);
+               return 1;
+       }
        bin_clear_free(ssid->eap.password, ssid->eap.password_len);
        ssid->eap.password = hash;
        ssid->eap.password_len = 16;
@@ -1236,6 +1503,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
 }
 
 
+#ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_password(const struct parse_data *data,
                                        struct wpa_ssid *ssid)
 {
@@ -1269,6 +1537,7 @@ static char * wpa_config_write_password(const struct parse_data *data,
 
        return buf;
 }
+#endif /* NO_CONFIG_WRITE */
 #endif /* IEEE8021X_EAPOL */
 
 
@@ -1298,7 +1567,7 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
        os_memcpy(key, buf, *len);
        str_clear_free(buf);
        res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
-       if (res >= 0 && (size_t) res < sizeof(title))
+       if (!os_snprintf_error(sizeof(title), res))
                wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
        return 0;
 }
@@ -1421,7 +1690,7 @@ static char * wpa_config_write_go_p2p_dev_addr(const struct parse_data *data,
        if (value == NULL)
                return NULL;
        res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
-       if (res < 0 || res >= 20) {
+       if (os_snprintf_error(20, res)) {
                os_free(value);
                return NULL;
        }
@@ -1435,53 +1704,10 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
                                            struct wpa_ssid *ssid, int line,
                                            const char *value)
 {
-       const char *pos;
-       u8 *buf, *n, addr[ETH_ALEN];
-       size_t count;
-
-       buf = NULL;
-       count = 0;
-
-       pos = value;
-       while (pos && *pos) {
-               while (*pos == ' ')
-                       pos++;
-
-               if (hwaddr_aton(pos, addr)) {
-                       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_array(buf, count + 1, ETH_ALEN);
-                       if (n == NULL) {
-                               os_free(buf);
-                               return -1;
-                       }
-                       buf = n;
-                       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);
-               }
-
-               pos = os_strchr(pos, ' ');
-       }
-
-       os_free(ssid->p2p_client_list);
-       ssid->p2p_client_list = buf;
-       ssid->num_p2p_clients = count;
-
-       return 0;
+       return wpa_config_parse_addr_list(data, line, value,
+                                         &ssid->p2p_client_list,
+                                         &ssid->num_p2p_clients,
+                                         "p2p_client_list", 0, 0);
 }
 
 
@@ -1489,34 +1715,9 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
 static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
                                               struct wpa_ssid *ssid)
 {
-       char *value, *end, *pos;
-       int res;
-       size_t i;
-
-       if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
-               return NULL;
-
-       value = os_malloc(20 * ssid->num_p2p_clients);
-       if (value == NULL)
-               return NULL;
-       pos = value;
-       end = value + 20 * ssid->num_p2p_clients;
-
-       for (i = ssid->num_p2p_clients; i > 0; i--) {
-               res = os_snprintf(pos, end - pos, MACSTR " ",
-                                 MAC2STR(ssid->p2p_client_list +
-                                         (i - 1) * ETH_ALEN));
-               if (res < 0 || res >= end - pos) {
-                       os_free(value);
-                       return NULL;
-               }
-               pos += res;
-       }
-
-       if (pos > value)
-               pos[-1] = '\0';
-
-       return value;
+       return wpa_config_write_addr_list(data, ssid->p2p_client_list,
+                                         ssid->num_p2p_clients,
+                                         "p2p_client_list");
 }
 #endif /* NO_CONFIG_WRITE */
 
@@ -1576,6 +1777,45 @@ static char * wpa_config_write_psk_list(const struct parse_data *data,
 
 #endif /* CONFIG_P2P */
 
+
+#ifdef CONFIG_MESH
+
+static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
+                                            struct wpa_ssid *ssid, int line,
+                                            const char *value)
+{
+       int *rates = wpa_config_parse_int_array(value);
+
+       if (rates == NULL) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'",
+                          line, value);
+               return -1;
+       }
+       if (rates[0] == 0) {
+               os_free(rates);
+               rates = NULL;
+       }
+
+       os_free(ssid->mesh_basic_rates);
+       ssid->mesh_basic_rates = rates;
+
+       return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
+                                               struct wpa_ssid *ssid)
+{
+       return wpa_config_write_freqs(data, ssid->mesh_basic_rates);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MESH */
+
+
 /* Helper macros for network block parser */
 
 #ifdef OFFSET
@@ -1664,10 +1904,13 @@ static char * wpa_config_write_psk_list(const struct parse_data *data,
  * functions.
  */
 static const struct parse_data ssid_fields[] = {
-       { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
+       { STR_RANGE(ssid, 0, SSID_MAX_LEN) },
        { INT_RANGE(scan_ssid, 0, 1) },
        { FUNC(bssid) },
+       { FUNC(bssid_blacklist) },
+       { FUNC(bssid_whitelist) },
        { FUNC_KEY(psk) },
+       { INT(mem_only_psk) },
        { FUNC(proto) },
        { FUNC(key_mgmt) },
        { INT(bg_scan_period) },
@@ -1676,6 +1919,8 @@ static const struct parse_data ssid_fields[] = {
        { FUNC(auth_alg) },
        { FUNC(scan_freq) },
        { FUNC(freq_list) },
+       { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT,
+                   VHT_CHANWIDTH_80P80MHZ) },
 #ifdef IEEE8021X_EAPOL
        { FUNC(eap) },
        { STR_LENe(identity) },
@@ -1690,6 +1935,7 @@ static const struct parse_data ssid_fields[] = {
        { STRe(subject_match) },
        { STRe(altsubject_match) },
        { STRe(domain_suffix_match) },
+       { STRe(domain_match) },
        { STRe(ca_cert2) },
        { STRe(ca_path2) },
        { STRe(client_cert2) },
@@ -1699,6 +1945,7 @@ static const struct parse_data ssid_fields[] = {
        { STRe(subject_match2) },
        { STRe(altsubject_match2) },
        { STRe(domain_suffix_match2) },
+       { STRe(domain_match2) },
        { STRe(phase1) },
        { STRe(phase2) },
        { STRe(pcsc) },
@@ -1717,6 +1964,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(eapol_flags) },
        { INTe(sim_num) },
        { STRe(openssl_ciphers) },
+       { INTe(erp) },
 #endif /* IEEE8021X_EAPOL */
        { FUNC_KEY(wep_key0) },
        { FUNC_KEY(wep_key1) },
@@ -1730,7 +1978,12 @@ static const struct parse_data ssid_fields[] = {
        { INTe(fragment_size) },
        { INTe(ocsp) },
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+       { INT_RANGE(mode, 0, 5) },
+       { INT_RANGE(no_auto_peer, 0, 1) },
+#else /* CONFIG_MESH */
        { INT_RANGE(mode, 0, 4) },
+#endif /* CONFIG_MESH */
        { INT_RANGE(proactive_key_caching, 0, 1) },
        { INT_RANGE(disabled, 0, 2) },
        { STR(id_str) },
@@ -1740,6 +1993,17 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(peerkey, 0, 1) },
        { INT_RANGE(mixed_cell, 0, 1) },
        { INT_RANGE(frequency, 0, 65000) },
+       { INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+       { INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
+#ifdef CONFIG_MESH
+       { FUNC(mesh_basic_rates) },
+       { INT(dot11MeshMaxRetries) },
+       { INT(dot11MeshRetryTimeout) },
+       { INT(dot11MeshConfirmTimeout) },
+       { INT(dot11MeshHoldingTimeout) },
+#endif /* CONFIG_MESH */
        { INT(wpa_ptk_rekey) },
        { STR(bgscan) },
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -1790,6 +2054,8 @@ static const struct parse_data ssid_fields[] = {
        { INT(update_identifier) },
 #endif /* CONFIG_HS20 */
        { INT_RANGE(mac_addr, 0, 2) },
+       { INT_RANGE(pbss, 0, 2) },
+       { INT_RANGE(wps_disabled, 0, 1) },
 };
 
 #undef OFFSET
@@ -1911,6 +2177,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        os_free(eap->subject_match);
        os_free(eap->altsubject_match);
        os_free(eap->domain_suffix_match);
+       os_free(eap->domain_match);
        os_free(eap->ca_cert2);
        os_free(eap->ca_path2);
        os_free(eap->client_cert2);
@@ -1920,6 +2187,7 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        os_free(eap->subject_match2);
        os_free(eap->altsubject_match2);
        os_free(eap->domain_suffix_match2);
+       os_free(eap->domain_match2);
        os_free(eap->phase1);
        os_free(eap->phase2);
        os_free(eap->pcsc);
@@ -1955,7 +2223,6 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
        struct psk_list_entry *psk;
 
        os_free(ssid->ssid);
-       os_memset(ssid->psk, 0, sizeof(ssid->psk));
        str_clear_free(ssid->passphrase);
        os_free(ssid->ext_psk);
 #ifdef IEEE8021X_EAPOL
@@ -1966,15 +2233,20 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
        os_free(ssid->freq_list);
        os_free(ssid->bgscan);
        os_free(ssid->p2p_client_list);
+       os_free(ssid->bssid_blacklist);
+       os_free(ssid->bssid_whitelist);
 #ifdef CONFIG_HT_OVERRIDES
        os_free(ssid->ht_mcs);
 #endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_MESH
+       os_free(ssid->mesh_basic_rates);
+#endif /* CONFIG_MESH */
        while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
                                    list))) {
                dl_list_del(&psk->list);
-               os_free(psk);
+               bin_clear_free(psk, sizeof(*psk));
        }
-       os_free(ssid);
+       bin_clear_free(ssid, sizeof(*ssid));
 }
 
 
@@ -2036,6 +2308,7 @@ void wpa_config_free(struct wpa_config *config)
 {
        struct wpa_ssid *ssid, *prev = NULL;
        struct wpa_cred *cred, *cprev;
+       int i;
 
        ssid = config->ssid;
        while (ssid) {
@@ -2054,6 +2327,8 @@ void wpa_config_free(struct wpa_config *config)
        wpa_config_flush_blobs(config);
 
        wpabuf_free(config->wps_vendor_ext_m1);
+       for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
+               wpabuf_free(config->wps_vendor_ext[i]);
        os_free(config->ctrl_interface);
        os_free(config->ctrl_interface_group);
        os_free(config->opensc_engine_path);
@@ -2082,7 +2357,14 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->sae_groups);
        wpabuf_free(config->ap_vendor_elements);
        os_free(config->osu_dir);
+       os_free(config->bgscan);
        os_free(config->wowlan_triggers);
+       os_free(config->fst_group_id);
+       os_free(config->sched_scan_plans);
+#ifdef CONFIG_MBO
+       os_free(config->non_pref_chan);
+#endif /* CONFIG_MBO */
+
        os_free(config);
 }
 
@@ -2218,6 +2500,12 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
        ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
        ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+       ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
+       ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
+       ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
+       ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
+#endif /* CONFIG_MESH */
 #ifdef CONFIG_HT_OVERRIDES
        ssid->disable_ht = DEFAULT_DISABLE_HT;
        ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
@@ -2259,7 +2547,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
  * @var: Variable name, e.g., "ssid"
  * @value: Variable value
  * @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
  *
  * This function can be used to set network configuration variables based on
  * both the configuration file and management interface input. The value
@@ -2280,7 +2569,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
                if (os_strcmp(var, field->name) != 0)
                        continue;
 
-               if (field->parser(field, ssid, line, value)) {
+               ret = field->parser(field, ssid, line, value);
+               if (ret < 0) {
                        if (line) {
                                wpa_printf(MSG_ERROR, "Line %d: failed to "
                                           "parse %s '%s'.", line, var, value);
@@ -2336,6 +2626,9 @@ int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
  */
 char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
 {
+#ifdef NO_CONFIG_WRITE
+       return NULL;
+#else /* NO_CONFIG_WRITE */
        const struct parse_data *field;
        char *key, *value;
        size_t i;
@@ -2381,6 +2674,7 @@ err:
                os_free(value++);
        os_free(props);
        return NULL;
+#endif /* NO_CONFIG_WRITE */
 }
 
 
@@ -2406,8 +2700,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
 
        for (i = 0; i < NUM_SSID_FIELDS; i++) {
                const struct parse_data *field = &ssid_fields[i];
-               if (os_strcmp(var, field->name) == 0)
-                       return field->writer(field, ssid);
+               if (os_strcmp(var, field->name) == 0) {
+                       char *ret = field->writer(field, ssid);
+
+                       if (ret && has_newline(ret)) {
+                               wpa_printf(MSG_ERROR,
+                                          "Found newline in value for %s; not returning it",
+                                          var);
+                               os_free(ret);
+                               ret = NULL;
+                       }
+
+                       return ret;
+               }
        }
 
        return NULL;
@@ -2592,6 +2897,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 
        if (os_strcmp(var, "password") == 0 &&
            os_strncmp(value, "ext:", 4) == 0) {
+               if (has_newline(value))
+                       return -1;
                str_clear_free(cred->password);
                cred->password = os_strdup(value);
                cred->ext_password = 1;
@@ -2642,9 +2949,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
        }
 
        val = wpa_config_parse_string(value, &len);
-       if (val == NULL) {
+       if (val == NULL ||
+           (os_strcmp(var, "excluded_ssid") != 0 &&
+            os_strcmp(var, "roaming_consortium") != 0 &&
+            os_strcmp(var, "required_roaming_consortium") != 0 &&
+            has_newline(val))) {
                wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
                           "value '%s'.", line, var, value);
+               os_free(val);
                return -1;
        }
 
@@ -2767,7 +3079,7 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
        if (os_strcmp(var, "excluded_ssid") == 0) {
                struct excluded_ssid *e;
 
-               if (len > MAX_SSID_LEN) {
+               if (len > SSID_MAX_LEN) {
                        wpa_printf(MSG_ERROR, "Line %d: invalid "
                                   "excluded_ssid length %d", line, (int) len);
                        os_free(val);
@@ -2868,12 +3180,18 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 
 static char * alloc_int_str(int val)
 {
+       const unsigned int bufsize = 20;
        char *buf;
+       int res;
 
-       buf = os_malloc(20);
+       buf = os_malloc(bufsize);
        if (buf == NULL)
                return NULL;
-       os_snprintf(buf, 20, "%d", val);
+       res = os_snprintf(buf, bufsize, "%d", val);
+       if (os_snprintf_error(bufsize, res)) {
+               os_free(buf);
+               buf = NULL;
+       }
        return buf;
 }
 
@@ -2944,7 +3262,7 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
                        ret = os_snprintf(pos, end - pos, "%s%u",
                                          i > 0 ? "\n" : "",
                                          cred->req_conn_capab_proto[i]);
-                       if (ret < 0 || ret >= end - pos)
+                       if (os_snprintf_error(end - pos, ret))
                                return buf;
                        pos += ret;
 
@@ -2956,7 +3274,7 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
                                                          "%s%d",
                                                          j > 0 ? "," : ":",
                                                          ports[j]);
-                                       if (ret < 0 || ret >= end - pos)
+                                       if (os_snprintf_error(end - pos, ret))
                                                return buf;
                                        pos += ret;
                                }
@@ -3025,7 +3343,7 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
                for (i = 0; i < cred->num_domain; i++) {
                        ret = os_snprintf(pos, end - pos, "%s%s",
                                          i > 0 ? "\n" : "", cred->domain[i]);
-                       if (ret < 0 || ret >= end - pos)
+                       if (os_snprintf_error(end - pos, ret))
                                return buf;
                        pos += ret;
                }
@@ -3090,7 +3408,7 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
                        ret = os_snprintf(pos, end - pos, "%s%s",
                                          i > 0 ? "\n" : "",
                                          wpa_ssid_txt(e->ssid, e->ssid_len));
-                       if (ret < 0 || ret >= end - pos)
+                       if (os_snprintf_error(end - pos, ret))
                                return buf;
                        pos += ret;
                }
@@ -3120,7 +3438,7 @@ char * wpa_config_get_cred_no_key(struct wpa_cred *cred, const char *var)
                                          i > 0 ? "\n" : "",
                                          p->fqdn, p->exact_match, p->priority,
                                          p->country);
-                       if (ret < 0 || ret >= end - pos)
+                       if (os_snprintf_error(end - pos, ret))
                                return buf;
                        pos += ret;
                }
@@ -3310,11 +3628,18 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
                return NULL;
        config->eapol_version = DEFAULT_EAPOL_VERSION;
        config->ap_scan = DEFAULT_AP_SCAN;
+       config->user_mpm = DEFAULT_USER_MPM;
+       config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
+       config->mesh_max_inactivity = DEFAULT_MESH_MAX_INACTIVITY;
+       config->dot11RSNASAERetransPeriod =
+               DEFAULT_DOT11_RSNA_SAE_RETRANS_PERIOD;
        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_freq_change_policy = DEFAULT_P2P_GO_FREQ_MOVE;
        config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
        config->p2p_optimize_listen_chan = DEFAULT_P2P_OPTIMIZE_LISTEN_CHAN;
+       config->p2p_go_ctwindow = DEFAULT_P2P_GO_CTWINDOW;
        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;
@@ -3328,6 +3653,12 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
        config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
        config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
+       config->cert_in_cb = DEFAULT_CERT_IN_CB;
+       config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+
+#ifdef CONFIG_MBO
+       config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
+#endif /* CONFIG_MBO */
 
        if (ctrl_interface)
                config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3367,6 +3698,8 @@ struct global_parse_data {
        char *name;
        int (*parser)(const struct global_parse_data *data,
                      struct wpa_config *config, int line, const char *value);
+       int (*get)(const char *name, struct wpa_config *config, long offset,
+                  char *buf, size_t buflen, int pretty_print);
        void *param1, *param2, *param3;
        unsigned int changed_flag;
 };
@@ -3432,6 +3765,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
                return -1;
        }
 
+       if (has_newline(pos)) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
+                          line, data->name);
+               return -1;
+       }
+
        tmp = os_strdup(pos);
        if (tmp == NULL)
                return -1;
@@ -3470,21 +3809,11 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
                                       struct wpa_config *config, int line,
                                       const char *pos)
 {
-       size_t len;
        struct wpabuf **dst, *tmp;
 
-       len = os_strlen(pos);
-       if (len & 0x01)
-               return -1;
-
-       tmp = wpabuf_alloc(len / 2);
-       if (tmp == NULL)
-               return -1;
-
-       if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
-               wpabuf_free(tmp);
+       tmp = wpabuf_parse_bin(pos);
+       if (!tmp)
                return -1;
-       }
 
        dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
        wpabuf_free(*dst);
@@ -3826,22 +4155,81 @@ static int wpa_config_process_no_ctrl_interface(
 #endif /* CONFIG_CTRL_IFACE */
 
 
+static int wpa_config_get_int(const char *name, struct wpa_config *config,
+                             long offset, char *buf, size_t buflen,
+                             int pretty_print)
+{
+       int *val = (int *) (((u8 *) config) + (long) offset);
+
+       if (pretty_print)
+               return os_snprintf(buf, buflen, "%s=%d\n", name, *val);
+       return os_snprintf(buf, buflen, "%d", *val);
+}
+
+
+static int wpa_config_get_str(const char *name, struct wpa_config *config,
+                             long offset, char *buf, size_t buflen,
+                             int pretty_print)
+{
+       char **val = (char **) (((u8 *) config) + (long) offset);
+       int res;
+
+       if (pretty_print)
+               res = os_snprintf(buf, buflen, "%s=%s\n", name,
+                                 *val ? *val : "null");
+       else if (!*val)
+               return -1;
+       else
+               res = os_snprintf(buf, buflen, "%s", *val);
+       if (os_snprintf_error(buflen, res))
+               res = -1;
+
+       return res;
+}
+
+
+#ifdef CONFIG_P2P
+static int wpa_config_get_ipv4(const char *name, struct wpa_config *config,
+                              long offset, char *buf, size_t buflen,
+                              int pretty_print)
+{
+       void *val = ((u8 *) config) + (long) offset;
+       int res;
+       char addr[INET_ADDRSTRLEN];
+
+       if (!val || !inet_ntop(AF_INET, val, addr, sizeof(addr)))
+               return -1;
+
+       if (pretty_print)
+               res = os_snprintf(buf, buflen, "%s=%s\n", name, addr);
+       else
+               res = os_snprintf(buf, buflen, "%s", addr);
+
+       if (os_snprintf_error(buflen, res))
+               res = -1;
+
+       return res;
+}
+#endif /* CONFIG_P2P */
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
 /* OFFSET: Get offset of a variable within the wpa_config structure */
 #define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
 
-#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
-#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
-#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
+#define FUNC(f) #f, wpa_config_process_ ## f, NULL, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL, NULL
+#define _INT(f) #f, wpa_global_config_parse_int, wpa_config_get_int, OFFSET(f)
 #define INT(f) _INT(f), NULL, NULL
 #define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
-#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
+#define _STR(f) #f, wpa_global_config_parse_str, wpa_config_get_str, OFFSET(f)
 #define STR(f) _STR(f), NULL, NULL
 #define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
-#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
-#define IPV4(f) #f, wpa_global_config_parse_ipv4, OFFSET(f), NULL, NULL
+#define BIN(f) #f, wpa_global_config_parse_bin, NULL, OFFSET(f), NULL, NULL
+#define IPV4(f) #f, wpa_global_config_parse_ipv4, wpa_config_get_ipv4,  \
+       OFFSET(f), NULL, NULL
 
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
@@ -3856,6 +4244,12 @@ static const struct global_parse_data global_fields[] = {
 #endif /* CONFIG_MACSEC */
        { INT(ap_scan), 0 },
        { FUNC(bgscan), 0 },
+#ifdef CONFIG_MESH
+       { INT(user_mpm), 0 },
+       { INT_RANGE(max_peer_links, 0, 255), 0 },
+       { INT(mesh_max_inactivity), 0 },
+       { INT(dot11RSNASAERetransPeriod), 0 },
+#endif /* CONFIG_MESH */
        { INT(disable_scan_offload), 0 },
        { INT(fast_reauth), 0 },
        { STR(opensc_engine_path), 0 },
@@ -3875,7 +4269,8 @@ static const struct global_parse_data global_fields[] = {
        { FUNC_NO_VAR(load_dynamic_eap), 0 },
 #ifdef CONFIG_WPS
        { FUNC(uuid), CFG_CHANGED_UUID },
-       { STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
+       { STR_RANGE(device_name, 0, WPS_DEV_NAME_MAX_LEN),
+         CFG_CHANGED_DEVICE_NAME },
        { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
        { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
        { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
@@ -3888,8 +4283,8 @@ static const struct global_parse_data global_fields[] = {
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
        { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
-       { INT(p2p_listen_reg_class), 0 },
-       { INT(p2p_listen_channel), 0 },
+       { INT(p2p_listen_reg_class), CFG_CHANGED_P2P_LISTEN_CHANNEL },
+       { INT(p2p_listen_channel), CFG_CHANGED_P2P_LISTEN_CHANNEL },
        { 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 },
@@ -3897,6 +4292,7 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(persistent_reconnect, 0, 1), 0 },
        { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
        { INT(p2p_group_idle), 0 },
+       { INT_RANGE(p2p_go_freq_change_policy, 0, P2P_GO_FREQ_MOVE_MAX), 0 },
        { INT_RANGE(p2p_passphrase_len, 8, 63),
          CFG_CHANGED_P2P_PASSPHRASE_LEN },
        { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
@@ -3906,12 +4302,14 @@ static const struct global_parse_data global_fields[] = {
        { INT(p2p_go_ht40), 0 },
        { INT(p2p_go_vht), 0 },
        { INT(p2p_disabled), 0 },
+       { INT_RANGE(p2p_go_ctwindow, 0, 127), 0 },
        { INT(p2p_no_group_iface), 0 },
        { INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
        { IPV4(ip_addr_go), 0 },
        { IPV4(ip_addr_mask), 0 },
        { IPV4(ip_addr_start), 0 },
        { IPV4(ip_addr_end), 0 },
+       { INT_RANGE(p2p_cli_probe, 0, 1), 0 },
 #endif /* CONFIG_P2P */
        { FUNC(country), CFG_CHANGED_COUNTRY },
        { INT(bss_max_count), 0 },
@@ -3955,6 +4353,22 @@ static const struct global_parse_data global_fields[] = {
        { INT(rand_addr_lifetime), 0 },
        { INT(preassoc_mac_addr), 0 },
        { INT(key_mgmt_offload), 0},
+       { INT(passive_scan), 0 },
+       { INT(reassoc_same_bss_optim), 0 },
+       { INT(wps_priority), 0},
+#ifdef CONFIG_FST
+       { STR_RANGE(fst_group_id, 1, FST_MAX_GROUP_ID_LEN), 0 },
+       { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
+       { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
+#endif /* CONFIG_FST */
+       { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
+       { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
+#ifdef CONFIG_MBO
+       { STR(non_pref_chan), 0 },
+       { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
+                   MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
+#endif /*CONFIG_MBO */
+       { INT(gas_address3), 0 },
 };
 
 #undef FUNC
@@ -3969,6 +4383,67 @@ static const struct global_parse_data global_fields[] = {
 #define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
 
 
+int wpa_config_dump_values(struct wpa_config *config, char *buf, size_t buflen)
+{
+       int result = 0;
+       size_t i;
+
+       for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+               const struct global_parse_data *field = &global_fields[i];
+               int tmp;
+
+               if (!field->get)
+                       continue;
+
+               tmp = field->get(field->name, config, (long) field->param1,
+                                buf, buflen, 1);
+               if (tmp < 0)
+                       return -1;
+               buf += tmp;
+               buflen -= tmp;
+               result += tmp;
+       }
+       return result;
+}
+
+
+int wpa_config_get_value(const char *name, struct wpa_config *config,
+                        char *buf, size_t buflen)
+{
+       size_t i;
+
+       for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+               const struct global_parse_data *field = &global_fields[i];
+
+               if (os_strcmp(name, field->name) != 0)
+                       continue;
+               if (!field->get)
+                       break;
+               return field->get(name, config, (long) field->param1,
+                                 buf, buflen, 0);
+       }
+
+       return -1;
+}
+
+
+int wpa_config_get_num_global_field_names(void)
+{
+       return NUM_GLOBAL_FIELDS;
+}
+
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
+{
+       if (i >= NUM_GLOBAL_FIELDS)
+               return NULL;
+
+       if (no_var)
+               *no_var = !global_fields[i].param1;
+       return global_fields[i].name;
+}
+
+
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
 {
        size_t i;