/*
* 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.
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
#include "p2p/p2p.h"
+#include "fst/fst.h"
#include "config.h"
/* 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);
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) {
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)
line, value);
return -1;
}
+
+ if (*dst == val)
+ return 1;
*dst = val;
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
#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)
#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)
}
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);
errors++;
}
+ if (!errors && ssid->proto == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
ssid->proto = val;
return errors ? -1 : 0;
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);
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;
}
#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 ? "" : " ");
}
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);
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'.",
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;
}
return buf;
+#endif /* CONFIG_NO_WPA */
}
#endif /* NO_CONFIG_WRITE */
return -1;
}
+ if (ssid->pairwise_cipher == val)
+ return 1;
wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
ssid->pairwise_cipher = val;
return 0;
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;
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;
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);
}
+#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_eap(const struct parse_data *data,
struct wpa_ssid *ssid)
{
return buf;
}
+#endif /* NO_CONFIG_WRITE */
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;
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;
}
+#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_password(const struct parse_data *data,
struct wpa_ssid *ssid)
{
return buf;
}
+#endif /* NO_CONFIG_WRITE */
#endif /* IEEE8021X_EAPOL */
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);
}
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 (os_snprintf_error(end - pos, res)) {
- 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 */
#ifdef CONFIG_MESH
-static int wpa_config_parse_mesh_ht_mode(const struct parse_data *data,
- struct wpa_ssid *ssid, int line,
- const char *value)
-{
- int htval = 0;
-
- if (os_strcmp(value, "NOHT") == 0)
- htval = CHAN_NO_HT;
- else if (os_strcmp(value, "HT20") == 0)
- htval = CHAN_HT20;
- else if (os_strcmp(value, "HT40-") == 0)
- htval = CHAN_HT40MINUS;
- else if (os_strcmp(value, "HT40+") == 0)
- htval = CHAN_HT40PLUS;
- else {
- wpa_printf(MSG_ERROR,
- "Line %d: no ht_mode configured.", line);
- return -1;
- }
-
- wpa_printf(MSG_MSGDUMP, "mesh_ht_mode: 0x%x", htval);
- ssid->mesh_ht_mode = htval;
- return 0;
-}
-
-
static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
#ifndef NO_CONFIG_WRITE
-static char * wpa_config_write_mesh_ht_mode(const struct parse_data *data,
- struct wpa_ssid *ssid)
-{
- char *val;
-
- switch (ssid->mesh_ht_mode) {
- default:
- val = NULL;
- break;
- case CHAN_NO_HT:
- val = "NOHT";
- break;
- case CHAN_HT20:
- val = "HT20";
- break;
- case CHAN_HT40MINUS:
- val = "HT40-";
- break;
- case CHAN_HT40PLUS:
- val = "HT40+";
- break;
- }
- return val ? os_strdup(val) : NULL;
-}
-
-
static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
struct wpa_ssid *ssid)
{
* 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) },
{ 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) },
{ STRe(subject_match) },
{ STRe(altsubject_match) },
{ STRe(domain_suffix_match) },
+ { STRe(domain_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
{ STRe(domain_suffix_match2) },
+ { STRe(domain_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
{ 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_ht_mode) },
{ FUNC(mesh_basic_rates) },
{ INT(dot11MeshMaxRetries) },
{ INT(dot11MeshRetryTimeout) },
{ INT(dot11MeshHoldingTimeout) },
#endif /* CONFIG_MESH */
{ INT(wpa_ptk_rekey) },
+ { INT(group_rekey) },
{ STR(bgscan) },
{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
#ifdef CONFIG_P2P
{ 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
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);
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);
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
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 */
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));
}
{
struct wpa_ssid *ssid, *prev = NULL;
struct wpa_cred *cred, *cprev;
+ int i;
ssid = config->ssid;
while (ssid) {
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);
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);
}
ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
- ssid->mesh_ht_mode = DEFAULT_MESH_HT_MODE;
ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
* @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
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);
*/
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;
return props;
err:
- value = *props;
- while (value)
- os_free(value++);
+ for (i = 0; props[i]; i++)
+ os_free(props[i]);
os_free(props);
return NULL;
+#endif /* NO_CONFIG_WRITE */
}
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;
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;
}
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;
}
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);
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;
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);
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;
};
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;
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)
+ tmp = wpabuf_parse_bin(pos);
+ if (!tmp)
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;
#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
{ 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 },
{ 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 },
#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 },
{ 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 },
{ 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 },
{ 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 },
+ { INT_RANGE(ftm_responder, 0, 1), 0 },
+ { INT_RANGE(ftm_initiator, 0, 1), 0 },
};
#undef FUNC
#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;