Global parser functions to return 1 when property unchanged

Currently, wpa_config_set(), the function that sets wpa_supplicant
per-network properties, returns 1 when a property it attempts to set is
unchanged. Its global parallel, wpa_config_process_global(), doesn't do
this even though much of the code is very similar. Change this, and
several of the parser functions, to resemble the per-network parser and
setter functions.

Signed-off-by: Matthew Wang <matthewmwang@chromium.org>
This commit is contained in:
Matthew Wang 2020-07-15 17:17:41 -07:00 committed by Jouni Malinen
parent a87173b1d1
commit 922fa09972
4 changed files with 80 additions and 7 deletions

View file

@ -70,6 +70,21 @@ static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
return buf->size - buf->used; return buf->size - buf->used;
} }
/**
* wpabuf_cmp - Check if two buffers contain the same data
* @a: wpabuf buffer
* @b: wpabuf buffer
* Returns: 0 if the two buffers contain the same data and non-zero otherwise
*/
static inline int wpabuf_cmp(const struct wpabuf *a, const struct wpabuf *b)
{
if (!a && !b)
return 0;
if (a && b && wpabuf_size(a) == wpabuf_size(b))
return os_memcmp(a->buf, b->buf, wpabuf_size(a));
return -1;
}
/** /**
* wpabuf_head - Get pointer to the head of the buffer data * wpabuf_head - Get pointer to the head of the buffer data
* @buf: wpabuf buffer * @buf: wpabuf buffer

View file

@ -4360,13 +4360,31 @@ void wpa_config_debug_dump_networks(struct wpa_config *config)
#endif /* CONFIG_NO_STDOUT_DEBUG */ #endif /* CONFIG_NO_STDOUT_DEBUG */
/**
* Structure for global configuration parsing. This data is used to implement a
* generic parser for the global interface configuration. The table of variables
* is defined below in this file (global_fields[]).
*/
struct global_parse_data { struct global_parse_data {
/* Configuration variable name */
char *name; char *name;
/* 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 global_parse_data *data, int (*parser)(const struct global_parse_data *data,
struct wpa_config *config, int line, const char *value); struct wpa_config *config, int line, const char *value);
/* Getter function to print the variable in text format to buf. */
int (*get)(const char *name, struct wpa_config *config, long offset, int (*get)(const char *name, struct wpa_config *config, long offset,
char *buf, size_t buflen, int pretty_print); char *buf, size_t buflen, int pretty_print);
/* Variable specific parameters for the parser. */
void *param1, *param2, *param3; void *param1, *param2, *param3;
/* Indicates which configuration variable has changed. */
unsigned int changed_flag; unsigned int changed_flag;
}; };
@ -4377,6 +4395,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
{ {
int val, *dst; int val, *dst;
char *end; char *end;
bool same;
dst = (int *) (((u8 *) config) + (long) data->param1); dst = (int *) (((u8 *) config) + (long) data->param1);
val = strtol(pos, &end, 0); val = strtol(pos, &end, 0);
@ -4385,6 +4404,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
line, pos); line, pos);
return -1; return -1;
} }
same = *dst == val;
*dst = val; *dst = val;
wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst); wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
@ -4405,7 +4425,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data,
return -1; return -1;
} }
return 0; return same;
} }
@ -4413,7 +4433,7 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
struct wpa_config *config, int line, struct wpa_config *config, int line,
const char *pos) const char *pos)
{ {
size_t len; size_t len, prev_len;
char **dst, *tmp; char **dst, *tmp;
len = os_strlen(pos); len = os_strlen(pos);
@ -4437,11 +4457,22 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
return -1; return -1;
} }
dst = (char **) (((u8 *) config) + (long) data->param1);
if (*dst)
prev_len = os_strlen(*dst);
else
prev_len = 0;
/* No change to the previously configured value */
if ((!(*dst) && !pos) ||
(*dst && pos && prev_len == len &&
os_memcmp(*dst, pos, len) == 0))
return 1;
tmp = os_strdup(pos); tmp = os_strdup(pos);
if (tmp == NULL) if (tmp == NULL)
return -1; return -1;
dst = (char **) (((u8 *) config) + (long) data->param1);
os_free(*dst); os_free(*dst);
*dst = tmp; *dst = tmp;
wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst); wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
@ -4482,6 +4513,10 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
return -1; return -1;
dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
if (wpabuf_cmp(*dst, tmp) == 0) {
wpabuf_free(tmp);
return 1;
}
wpabuf_free(*dst); wpabuf_free(*dst);
*dst = tmp; *dst = tmp;
wpa_printf(MSG_DEBUG, "%s", data->name); wpa_printf(MSG_DEBUG, "%s", data->name);
@ -4523,6 +4558,8 @@ static int wpa_global_config_parse_ipv4(const struct global_parse_data *data,
return -1; return -1;
dst = (u32 *) (((u8 *) config) + (long) data->param1); dst = (u32 *) (((u8 *) config) + (long) data->param1);
if (os_memcmp(dst, &addr.u.v4.s_addr, 4) == 0)
return 1;
os_memcpy(dst, &addr.u.v4.s_addr, 4); os_memcpy(dst, &addr.u.v4.s_addr, 4);
wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name, wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name,
WPA_GET_BE32((u8 *) dst)); WPA_GET_BE32((u8 *) dst));
@ -4540,6 +4577,8 @@ static int wpa_config_process_country(const struct global_parse_data *data,
wpa_printf(MSG_DEBUG, "Invalid country set"); wpa_printf(MSG_DEBUG, "Invalid country set");
return -1; return -1;
} }
if (pos[0] == config->country[0] && pos[1] == config->country[1])
return 1;
config->country[0] = pos[0]; config->country[0] = pos[0];
config->country[1] = pos[1]; config->country[1] = pos[1];
wpa_printf(MSG_DEBUG, "country='%c%c'", wpa_printf(MSG_DEBUG, "country='%c%c'",
@ -5159,6 +5198,19 @@ const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
} }
/**
* wpa_config_process_global - Set a variable in global configuration
* @config: Pointer to global configuration data
* @pos: Name and value in the format "{name}={value}"
* @line: Line number in configuration file or 0 if not used
* Returns: 0 on success with a possible change in value, 1 on success with no
* change to previously configured value, or -1 on failure
*
* This function can be used to set global configuration variables based on
* both the configuration file and management interface input. The value
* parameter must be in the same format as the text-based configuration file is
* using. For example, strings are using double quotation marks.
*/
int wpa_config_process_global(struct wpa_config *config, char *pos, int line) int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
{ {
size_t i; size_t i;
@ -5171,11 +5223,14 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
pos[flen] != '=') pos[flen] != '=')
continue; continue;
if (field->parser(field, config, line, pos + flen + 1)) { ret = field->parser(field, config, line, pos + flen + 1);
if (ret < 0) {
wpa_printf(MSG_ERROR, "Line %d: failed to " wpa_printf(MSG_ERROR, "Line %d: failed to "
"parse '%s'.", line, pos); "parse '%s'.", line, pos);
ret = -1; ret = -1;
} }
if (ret == 1)
break;
if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN) if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN)
config->wps_nfc_pw_from_config = 1; config->wps_nfc_pw_from_config = 1;
config->changed_parameters |= field->changed_flag; config->changed_parameters |= field->changed_flag;

View file

@ -898,6 +898,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
ret = wpa_config_process_global(wpa_s->conf, cmd, -1); ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
if (ret == 0) if (ret == 0)
wpa_supplicant_update_config(wpa_s); wpa_supplicant_update_config(wpa_s);
else if (ret == 1)
ret = 0;
} }
return ret; return ret;

View file

@ -3983,14 +3983,15 @@ dbus_bool_t wpas_dbus_setter_iface_global(
return FALSE; return FALSE;
} }
if (wpa_config_process_global(wpa_s->conf, buf, -1)) { ret = wpa_config_process_global(wpa_s->conf, buf, -1);
if (ret < 0) {
dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
"Failed to set interface property %s", "Failed to set interface property %s",
property_desc->dbus_property); property_desc->dbus_property);
return FALSE; return FALSE;
} } else if (ret == 0) {
wpa_supplicant_update_config(wpa_s); wpa_supplicant_update_config(wpa_s);
}
return TRUE; return TRUE;
} }