From 922fa099721903b106a7bc1ccd1ffe8c4a7bce69 Mon Sep 17 00:00:00 2001 From: Matthew Wang Date: Wed, 15 Jul 2020 17:17:41 -0700 Subject: [PATCH] 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 --- src/utils/wpabuf.h | 15 ++++++ wpa_supplicant/config.c | 63 +++++++++++++++++++++++-- wpa_supplicant/ctrl_iface.c | 2 + wpa_supplicant/dbus/dbus_new_handlers.c | 7 +-- 4 files changed, 80 insertions(+), 7 deletions(-) diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h index 01da41b32..b2a54b22f 100644 --- a/src/utils/wpabuf.h +++ b/src/utils/wpabuf.h @@ -70,6 +70,21 @@ static inline size_t wpabuf_tailroom(const struct wpabuf *buf) 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 * @buf: wpabuf buffer diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 154687d30..0cbd09c86 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -4360,13 +4360,31 @@ void wpa_config_debug_dump_networks(struct wpa_config *config) #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 { + /* Configuration variable 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, 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, char *buf, size_t buflen, int pretty_print); + + /* Variable specific parameters for the parser. */ void *param1, *param2, *param3; + + /* Indicates which configuration variable has changed. */ unsigned int changed_flag; }; @@ -4377,6 +4395,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data, { int val, *dst; char *end; + bool same; dst = (int *) (((u8 *) config) + (long) data->param1); val = strtol(pos, &end, 0); @@ -4385,6 +4404,7 @@ static int wpa_global_config_parse_int(const struct global_parse_data *data, line, pos); return -1; } + same = *dst == val; *dst = val; 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 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, const char *pos) { - size_t len; + size_t len, prev_len; char **dst, *tmp; len = os_strlen(pos); @@ -4437,11 +4457,22 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data, 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); if (tmp == NULL) return -1; - dst = (char **) (((u8 *) config) + (long) data->param1); os_free(*dst); *dst = tmp; 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; dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1); + if (wpabuf_cmp(*dst, tmp) == 0) { + wpabuf_free(tmp); + return 1; + } wpabuf_free(*dst); *dst = tmp; 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; 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); wpa_printf(MSG_DEBUG, "%s = 0x%x", data->name, 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"); return -1; } + if (pos[0] == config->country[0] && pos[1] == config->country[1]) + return 1; config->country[0] = pos[0]; config->country[1] = pos[1]; 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) { size_t i; @@ -5171,11 +5223,14 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) pos[flen] != '=') 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 " "parse '%s'.", line, pos); ret = -1; } + if (ret == 1) + break; if (field->changed_flag == CFG_CHANGED_NFC_PASSWORD_TOKEN) config->wps_nfc_pw_from_config = 1; config->changed_parameters |= field->changed_flag; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 5048ee83e..127b5fe0b 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -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); if (ret == 0) wpa_supplicant_update_config(wpa_s); + else if (ret == 1) + ret = 0; } return ret; diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 1c3f33367..defb9d405 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -3983,14 +3983,15 @@ dbus_bool_t wpas_dbus_setter_iface_global( 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, "Failed to set interface property %s", property_desc->dbus_property); return FALSE; + } else if (ret == 0) { + wpa_supplicant_update_config(wpa_s); } - - wpa_supplicant_update_config(wpa_s); return TRUE; }