SAE: Allow enabled groups to be configured
[mech_eap.git] / wpa_supplicant / config.c
index fc3205e..136deea 100644 (file)
@@ -13,6 +13,7 @@
 #include "crypto/sha1.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap.h"
+#include "p2p/p2p.h"
 #include "config.h"
 
 
@@ -52,42 +53,6 @@ struct parse_data {
 };
 
 
-static char * wpa_config_parse_string(const char *value, size_t *len)
-{
-       if (*value == '"') {
-               const char *pos;
-               char *str;
-               value++;
-               pos = os_strrchr(value, '"');
-               if (pos == NULL || pos[1] != '\0')
-                       return NULL;
-               *len = pos - value;
-               str = os_malloc(*len + 1);
-               if (str == NULL)
-                       return NULL;
-               os_memcpy(str, value, *len);
-               str[*len] = '\0';
-               return str;
-       } else {
-               u8 *str;
-               size_t tlen, hlen = os_strlen(value);
-               if (hlen & 1)
-                       return NULL;
-               tlen = hlen / 2;
-               str = os_malloc(tlen + 1);
-               if (str == NULL)
-                       return NULL;
-               if (hexstr2bin(value, str, tlen)) {
-                       os_free(str);
-                       return NULL;
-               }
-               str[tlen] = '\0';
-               *len = tlen;
-               return (char *) str;
-       }
-}
-
-
 static int wpa_config_parse_str(const struct parse_data *data,
                                struct wpa_ssid *ssid,
                                int line, const char *value)
@@ -148,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;
@@ -323,6 +276,21 @@ static int wpa_config_parse_psk(const struct parse_data *data,
                                struct wpa_ssid *ssid, int line,
                                const char *value)
 {
+#ifdef CONFIG_EXT_PASSWORD
+       if (os_strncmp(value, "ext:", 4) == 0) {
+               os_free(ssid->passphrase);
+               ssid->passphrase = NULL;
+               ssid->psk_set = 0;
+               os_free(ssid->ext_psk);
+               ssid->ext_psk = os_strdup(value + 4);
+               if (ssid->ext_psk == NULL)
+                       return -1;
+               wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+                          ssid->ext_psk);
+               return 0;
+       }
+#endif /* CONFIG_EXT_PASSWORD */
+
        if (*value == '"') {
 #ifndef CONFIG_NO_PBKDF2
                const char *pos;
@@ -380,6 +348,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
 static char * wpa_config_write_psk(const struct parse_data *data,
                                   struct wpa_ssid *ssid)
 {
+#ifdef CONFIG_EXT_PASSWORD
+       if (ssid->ext_psk) {
+               size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+               char *buf = os_malloc(len);
+               if (buf == NULL)
+                       return NULL;
+               os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+               return buf;
+       }
+#endif /* CONFIG_EXT_PASSWORD */
+
        if (ssid->passphrase)
                return wpa_config_write_string_ascii(
                        (const u8 *) ssid->passphrase,
@@ -525,6 +504,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);
@@ -664,6 +649,8 @@ static int wpa_config_parse_cipher(int line, const char *value)
                *end = '\0';
                if (os_strcmp(start, "CCMP") == 0)
                        val |= WPA_CIPHER_CCMP;
+               else if (os_strcmp(start, "GCMP") == 0)
+                       val |= WPA_CIPHER_GCMP;
                else if (os_strcmp(start, "TKIP") == 0)
                        val |= WPA_CIPHER_TKIP;
                else if (os_strcmp(start, "WEP104") == 0)
@@ -715,6 +702,16 @@ static char * wpa_config_write_cipher(int cipher)
                pos += ret;
        }
 
+       if (cipher & WPA_CIPHER_GCMP) {
+               ret = os_snprintf(pos, end - pos, "%sGCMP",
+                                 pos == buf ? "" : " ");
+               if (ret < 0 || ret >= end - pos) {
+                       end[-1] = '\0';
+                       return buf;
+               }
+               pos += ret;
+       }
+
        if (cipher & WPA_CIPHER_TKIP) {
                ret = os_snprintf(pos, end - pos, "%sTKIP",
                                  pos == buf ? "" : " ");
@@ -768,7 +765,8 @@ 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_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+                   WPA_CIPHER_NONE)) {
                wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
                           "(0x%x).", line, val);
                return -1;
@@ -797,8 +795,8 @@ 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_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+                   WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
                wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
                           "(0x%x).", line, val);
                return -1;
@@ -918,9 +916,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;
@@ -928,7 +924,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;
 
@@ -939,7 +935,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;
@@ -967,7 +963,7 @@ 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;
        os_free(ssid->scan_freq);
@@ -983,7 +979,7 @@ 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;
        os_free(ssid->freq_list);
@@ -1068,8 +1064,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);
@@ -1099,7 +1095,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;
@@ -1110,6 +1106,7 @@ static int wpa_config_parse_eap(const struct parse_data *data,
 
        wpa_hexdump(MSG_MSGDUMP, "eap methods",
                    (u8 *) methods, num_methods * sizeof(*methods));
+       os_free(ssid->eap.eap_methods);
        ssid->eap.eap_methods = methods;
        return errors ? -1 : 0;
 }
@@ -1164,6 +1161,20 @@ static int wpa_config_parse_password(const struct parse_data *data,
                return 0;
        }
 
+#ifdef CONFIG_EXT_PASSWORD
+       if (os_strncmp(value, "ext:", 4) == 0) {
+               char *name = os_strdup(value + 4);
+               if (name == NULL)
+                       return -1;
+               os_free(ssid->eap.password);
+               ssid->eap.password = (u8 *) name;
+               ssid->eap.password_len = os_strlen(name);
+               ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+               ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+               return 0;
+       }
+#endif /* CONFIG_EXT_PASSWORD */
+
        if (os_strncmp(value, "hash:", 5) != 0) {
                char *tmp;
                size_t res_len;
@@ -1181,6 +1192,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
                ssid->eap.password = (u8 *) tmp;
                ssid->eap.password_len = res_len;
                ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+               ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
 
                return 0;
        }
@@ -1209,6 +1221,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
        ssid->eap.password = hash;
        ssid->eap.password_len = 16;
        ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+       ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
 
        return 0;
 }
@@ -1222,6 +1235,17 @@ static char * wpa_config_write_password(const struct parse_data *data,
        if (ssid->eap.password == NULL)
                return NULL;
 
+#ifdef CONFIG_EXT_PASSWORD
+       if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+               buf = os_zalloc(4 + ssid->eap.password_len + 1);
+               if (buf == NULL)
+                       return NULL;
+               os_memcpy(buf, "ext:", 4);
+               os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+               return buf;
+       }
+#endif /* CONFIG_EXT_PASSWORD */
+
        if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
                return wpa_config_write_string(
                        ssid->eap.password, ssid->eap.password_len);
@@ -1257,6 +1281,11 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
                os_free(buf);
                return -1;
        }
+       if (*len && *len != 5 && *len != 13 && *len != 16) {
+               wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+                          "this network block will be ignored",
+                          line, (unsigned int) *len);
+       }
        os_memcpy(key, buf, *len);
        os_free(buf);
        res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
@@ -1364,18 +1393,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);
@@ -1409,10 +1447,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;
@@ -1523,6 +1561,7 @@ static const struct parse_data ssid_fields[] = {
        { FUNC_KEY(psk) },
        { FUNC(proto) },
        { FUNC(key_mgmt) },
+       { INT(bg_scan_period) },
        { FUNC(pairwise) },
        { FUNC(group) },
        { FUNC(auth_alg) },
@@ -1586,7 +1625,7 @@ 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) },
@@ -1596,11 +1635,14 @@ static const struct parse_data ssid_fields[] = {
 #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 */
+       { INT(ap_max_inactivity) },
+       { INT(dtim_period) },
 };
 
 #undef OFFSET
@@ -1654,8 +1696,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;
 
@@ -1761,6 +1803,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
 {
        os_free(ssid->ssid);
        os_free(ssid->passphrase);
+       os_free(ssid->ext_psk);
 #ifdef IEEE8021X_EAPOL
        eap_peer_config_free(&ssid->eap);
 #endif /* IEEE8021X_EAPOL */
@@ -1788,6 +1831,10 @@ void wpa_config_free_cred(struct wpa_cred *cred)
        os_free(cred->imsi);
        os_free(cred->milenage);
        os_free(cred->domain);
+       os_free(cred->eap_method);
+       os_free(cred->phase1);
+       os_free(cred->phase2);
+       os_free(cred->excluded_ssid);
        os_free(cred);
 }
 
@@ -1831,6 +1878,7 @@ void wpa_config_free(struct wpa_config *config)
        }
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 
+       wpabuf_free(config->wps_vendor_ext_m1);
        os_free(config->ctrl_interface);
        os_free(config->ctrl_interface_group);
        os_free(config->opensc_engine_path);
@@ -1847,6 +1895,13 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->config_methods);
        os_free(config->p2p_ssid_postfix);
        os_free(config->pssid);
+       os_free(config->p2p_pref_chan);
+       os_free(config->autoscan);
+       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);
        os_free(config);
 }
 
@@ -1974,6 +2029,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
        ssid->pairwise_cipher = DEFAULT_PAIRWISE;
        ssid->group_cipher = DEFAULT_GROUP;
        ssid->key_mgmt = DEFAULT_KEY_MGMT;
+       ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
 #ifdef IEEE8021X_EAPOL
        ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
        ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
@@ -1982,10 +2038,15 @@ 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 */
+       ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+       ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
 }
 
 
@@ -2080,7 +2141,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;
 
@@ -2208,8 +2269,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
 void wpa_config_update_psk(struct wpa_ssid *ssid)
 {
 #ifndef CONFIG_NO_PBKDF2
-       pbkdf2_sha1(ssid->passphrase,
-                   (char *) ssid->ssid, ssid->ssid_len, 4096,
+       pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
                    ssid->psk, PMK_LEN);
        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
                        ssid->psk, PMK_LEN);
@@ -2229,6 +2289,36 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
                return 0;
        }
 
+       if (os_strcmp(var, "pcsc") == 0) {
+               cred->pcsc = atoi(value);
+               return 0;
+       }
+
+       if (os_strcmp(var, "eap") == 0) {
+               struct eap_method_type method;
+               method.method = eap_peer_get_type(value, &method.vendor);
+               if (method.vendor == EAP_VENDOR_IETF &&
+                   method.method == EAP_TYPE_NONE) {
+                       wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+                                  "for a credential", line, value);
+                       return -1;
+               }
+               os_free(cred->eap_method);
+               cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+               if (cred->eap_method == NULL)
+                       return -1;
+               os_memcpy(cred->eap_method, &method, sizeof(method));
+               return 0;
+       }
+
+       if (os_strcmp(var, "password") == 0 &&
+           os_strncmp(value, "ext:", 4) == 0) {
+               os_free(cred->password);
+               cred->password = os_strdup(value);
+               cred->ext_password = 1;
+               return 0;
+       }
+
        val = wpa_config_parse_string(value, &len);
        if (val == NULL) {
                wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
@@ -2251,6 +2341,7 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
        if (os_strcmp(var, "password") == 0) {
                os_free(cred->password);
                cred->password = val;
+               cred->ext_password = 0;
                return 0;
        }
 
@@ -2296,6 +2387,60 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
                return 0;
        }
 
+       if (os_strcmp(var, "phase1") == 0) {
+               os_free(cred->phase1);
+               cred->phase1 = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "phase2") == 0) {
+               os_free(cred->phase2);
+               cred->phase2 = val;
+               return 0;
+       }
+
+       if (os_strcmp(var, "roaming_consortium") == 0) {
+               if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+                       wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                  "roaming_consortium length %d (3..15 "
+                                  "expected)", line, (int) len);
+                       os_free(val);
+                       return -1;
+               }
+               os_memcpy(cred->roaming_consortium, val, len);
+               cred->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);
@@ -2466,6 +2611,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)
@@ -2475,11 +2629,16 @@ 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->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);
@@ -2588,6 +2747,35 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
 }
 
 
+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);
+               return -1;
+       }
+
+       dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+       wpabuf_free(*dst);
+       *dst = tmp;
+       wpa_printf(MSG_DEBUG, "%s", data->name);
+
+       return 0;
+}
+
+
 static int wpa_config_process_country(const struct global_parse_data *data,
                                      struct wpa_config *config, int line,
                                      const char *pos)
@@ -2662,6 +2850,43 @@ static int wpa_config_process_os_version(const struct global_parse_data *data,
        return 0;
 }
 
+
+static int wpa_config_process_wps_vendor_ext_m1(
+       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 wps_vendor_ext_m1", 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 wps_vendor_ext_m1", line);
+                       wpabuf_free(tmp);
+                       return -1;
+               }
+
+               wpabuf_free(config->wps_vendor_ext_m1);
+               config->wps_vendor_ext_m1 = tmp;
+       } else {
+               wpa_printf(MSG_ERROR, "Can not allocate "
+                          "memory for wps_vendor_ext_m1");
+               return -1;
+       }
+
+       return 0;
+}
+
 #endif /* CONFIG_WPS */
 
 #ifdef CONFIG_P2P
@@ -2685,6 +2910,56 @@ static int wpa_config_process_sec_device_type(
        config->num_sec_device_types++;
        return 0;
 }
+
+
+static int wpa_config_process_p2p_pref_chan(
+       const struct global_parse_data *data,
+       struct wpa_config *config, int line, const char *pos)
+{
+       struct p2p_channel *pref = NULL, *n;
+       unsigned int num = 0;
+       const char *pos2;
+       u8 op_class, chan;
+
+       /* format: class:chan,class:chan,... */
+
+       while (*pos) {
+               op_class = atoi(pos);
+               pos2 = os_strchr(pos, ':');
+               if (pos2 == NULL)
+                       goto fail;
+               pos2++;
+               chan = atoi(pos2);
+
+               n = os_realloc_array(pref, num + 1,
+                                    sizeof(struct p2p_channel));
+               if (n == NULL)
+                       goto fail;
+               pref = n;
+               pref[num].op_class = op_class;
+               pref[num].chan = chan;
+               num++;
+
+               pos = os_strchr(pos2, ',');
+               if (pos == NULL)
+                       break;
+               pos++;
+       }
+
+       os_free(config->p2p_pref_chan);
+       config->p2p_pref_chan = pref;
+       config->num_p2p_pref_chan = num;
+       wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
+                   (u8 *) config->p2p_pref_chan,
+                   config->num_p2p_pref_chan * sizeof(struct p2p_channel));
+
+       return 0;
+
+fail:
+       os_free(pref);
+       wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
+       return -1;
+}
 #endif /* CONFIG_P2P */
 
 
@@ -2702,6 +2977,24 @@ 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;
+}
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -2716,6 +3009,7 @@ static int wpa_config_process_hessid(
 #define _STR(f) #f, wpa_global_config_parse_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
 
 static const struct global_parse_data global_fields[] = {
 #ifdef CONFIG_CTRL_IFACE
@@ -2724,6 +3018,7 @@ static const struct global_parse_data global_fields[] = {
 #endif /* CONFIG_CTRL_IFACE */
        { INT_RANGE(eapol_version, 1, 2), 0 },
        { INT(ap_scan), 0 },
+       { INT(disable_scan_offload), 0 },
        { INT(fast_reauth), 0 },
        { STR(opensc_engine_path), 0 },
        { STR(pkcs11_engine_path), 0 },
@@ -2749,6 +3044,7 @@ static const struct global_parse_data global_fields[] = {
        { FUNC(os_version), CFG_CHANGED_OS_VERSION },
        { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
        { INT_RANGE(wps_cred_processing, 0, 2), 0 },
+       { FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
        { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
@@ -2761,17 +3057,37 @@ 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 },
+       { FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+       { INT(p2p_go_ht40), 0 },
+       { INT(p2p_disabled), 0 },
+       { INT(p2p_no_group_iface), 0 },
 #endif /* CONFIG_P2P */
        { FUNC(country), CFG_CHANGED_COUNTRY },
        { INT(bss_max_count), 0 },
        { INT(bss_expiration_age), 0 },
        { INT(bss_expiration_scan_count), 0 },
        { INT_RANGE(filter_ssids, 0, 1), 0 },
+       { INT_RANGE(filter_rssi, -100, 0), 0 },
        { INT(max_num_sta), 0 },
        { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
+#ifdef CONFIG_HS20
+       { INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
        { INT_RANGE(interworking, 0, 1), 0 },
        { FUNC(hessid), 0 },
-       { INT_RANGE(access_network_type, 0, 15), 0 }
+       { 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(p2p_go_max_inactivity), 0 },
+       { INT_RANGE(auto_interworking, 0, 1), 0 },
+       { INT(okc), 0 },
+       { INT(pmf), 0 },
+       { FUNC(sae_groups), 0 },
 };
 
 #undef FUNC
@@ -2781,6 +3097,7 @@ static const struct global_parse_data global_fields[] = {
 #undef _STR
 #undef STR
 #undef STR_RANGE
+#undef BIN
 #define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
 
 
@@ -2805,6 +3122,25 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
                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'.",