1  /*
2   * WPA Supplicant / dbus-based control interface
3   * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
4   * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
5   *
6   * This software may be distributed under the terms of the BSD license.
7   * See README for more details.
8   */
9  
10  #include "utils/includes.h"
11  
12  #include "utils/common.h"
13  #include "utils/eloop.h"
14  #include "drivers/driver.h"
15  #include "dbus_common.h"
16  #include "dbus_common_i.h"
17  #include "dbus_new.h"
18  #include "dbus_new_helpers.h"
19  #include "dbus_new_handlers.h"
20  #include "dbus_dict_helpers.h"
21  
22  
fill_dict_with_properties(DBusMessageIter * dict_iter,const struct wpa_dbus_property_desc * props,const char * interface,void * user_data,DBusError * error)23  static dbus_bool_t fill_dict_with_properties(
24  	DBusMessageIter *dict_iter,
25  	const struct wpa_dbus_property_desc *props,
26  	const char *interface, void *user_data, DBusError *error)
27  {
28  	DBusMessageIter entry_iter;
29  	const struct wpa_dbus_property_desc *dsc;
30  
31  	for (dsc = props; dsc && dsc->dbus_property; dsc++) {
32  		/* Only return properties for the requested D-Bus interface */
33  		if (os_strncmp(dsc->dbus_interface, interface,
34  			       WPAS_DBUS_INTERFACE_MAX) != 0)
35  			continue;
36  
37  		/* Skip write-only properties */
38  		if (dsc->getter == NULL)
39  			continue;
40  
41  		if (!dbus_message_iter_open_container(dict_iter,
42  						      DBUS_TYPE_DICT_ENTRY,
43  						      NULL, &entry_iter) ||
44  		    !dbus_message_iter_append_basic(&entry_iter,
45  						    DBUS_TYPE_STRING,
46  						    &dsc->dbus_property))
47  			goto error;
48  
49  		/* An error getting a property fails the request entirely */
50  		if (!dsc->getter(dsc, &entry_iter, error, user_data)) {
51  			wpa_printf(MSG_INFO,
52  				   "dbus: %s dbus_interface=%s dbus_property=%s getter failed",
53  				   __func__, dsc->dbus_interface,
54  				   dsc->dbus_property);
55  			return FALSE;
56  		}
57  
58  		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
59  			goto error;
60  	}
61  
62  	return TRUE;
63  
64  error:
65  	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
66  	return FALSE;
67  }
68  
69  
70  /**
71   * get_all_properties - Responds for GetAll properties calls on object
72   * @message: Message with GetAll call
73   * @interface: interface name which properties will be returned
74   * @property_dsc: list of object's properties
75   * Returns: Message with dict of variants as argument with properties values
76   *
77   * Iterates over all properties registered with object and execute getters
78   * of those, which are readable and which interface matches interface
79   * specified as argument. Returned message contains one dict argument
80   * with properties names as keys and theirs values as values.
81   */
get_all_properties(DBusMessage * message,char * interface,struct wpa_dbus_object_desc * obj_dsc)82  static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
83  					struct wpa_dbus_object_desc *obj_dsc)
84  {
85  	DBusMessage *reply;
86  	DBusMessageIter iter, dict_iter;
87  	DBusError error;
88  
89  	reply = dbus_message_new_method_return(message);
90  	if (reply == NULL)
91  		return wpas_dbus_error_no_memory(message);
92  
93  	dbus_message_iter_init_append(reply, &iter);
94  	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
95  		dbus_message_unref(reply);
96  		return wpas_dbus_error_no_memory(message);
97  	}
98  
99  	dbus_error_init(&error);
100  	if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
101  				       interface, obj_dsc->user_data, &error)) {
102  		wpa_dbus_dict_close_write(&iter, &dict_iter);
103  		dbus_message_unref(reply);
104  		reply = wpas_dbus_reply_new_from_error(
105  			message, &error, DBUS_ERROR_INVALID_ARGS,
106  			"No readable properties in this interface");
107  		dbus_error_free(&error);
108  		return reply;
109  	}
110  
111  	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
112  		dbus_message_unref(reply);
113  		return wpas_dbus_error_no_memory(message);
114  	}
115  
116  	return reply;
117  }
118  
119  
is_signature_correct(DBusMessage * message,const struct wpa_dbus_method_desc * method_dsc)120  static int is_signature_correct(DBusMessage *message,
121  				const struct wpa_dbus_method_desc *method_dsc)
122  {
123  	/* According to DBus documentation max length of signature is 255 */
124  #define MAX_SIG_LEN 256
125  	char registered_sig[MAX_SIG_LEN], *pos;
126  	const char *sig = dbus_message_get_signature(message);
127  	int ret;
128  	const struct wpa_dbus_argument *arg;
129  
130  	pos = registered_sig;
131  	*pos = '\0';
132  
133  	for (arg = method_dsc->args; arg && arg->name; arg++) {
134  		if (arg->dir == ARG_IN) {
135  			size_t blen = registered_sig + MAX_SIG_LEN - pos;
136  
137  			ret = os_snprintf(pos, blen, "%s", arg->type);
138  			if (os_snprintf_error(blen, ret))
139  				return 0;
140  			pos += ret;
141  		}
142  	}
143  
144  	return !os_strncmp(registered_sig, sig, MAX_SIG_LEN);
145  }
146  
147  
properties_get_all(DBusMessage * message,char * interface,struct wpa_dbus_object_desc * obj_dsc)148  static DBusMessage * properties_get_all(DBusMessage *message, char *interface,
149  					struct wpa_dbus_object_desc *obj_dsc)
150  {
151  	if (os_strcmp(dbus_message_get_signature(message), "s") != 0)
152  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
153  					      NULL);
154  
155  	return get_all_properties(message, interface, obj_dsc);
156  }
157  
158  
properties_get(DBusMessage * message,const struct wpa_dbus_property_desc * dsc,void * user_data)159  static DBusMessage * properties_get(DBusMessage *message,
160  				    const struct wpa_dbus_property_desc *dsc,
161  				    void *user_data)
162  {
163  	DBusMessage *reply;
164  	DBusMessageIter iter;
165  	DBusError error;
166  
167  	if (os_strcmp(dbus_message_get_signature(message), "ss")) {
168  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
169  					      NULL);
170  	}
171  
172  	if (dsc->getter == NULL) {
173  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
174  					      "Property is write-only");
175  	}
176  
177  	reply = dbus_message_new_method_return(message);
178  	dbus_message_iter_init_append(reply, &iter);
179  
180  	dbus_error_init(&error);
181  	if (dsc->getter(dsc, &iter, &error, user_data) == FALSE) {
182  		dbus_message_unref(reply);
183  		reply = wpas_dbus_reply_new_from_error(
184  			message, &error, DBUS_ERROR_FAILED,
185  			"Failed to read property");
186  		dbus_error_free(&error);
187  	}
188  
189  	return reply;
190  }
191  
192  
properties_set(DBusMessage * message,const struct wpa_dbus_property_desc * dsc,void * user_data)193  static DBusMessage * properties_set(DBusMessage *message,
194  				    const struct wpa_dbus_property_desc *dsc,
195  				    void *user_data)
196  {
197  	DBusMessage *reply;
198  	DBusMessageIter iter;
199  	DBusError error;
200  
201  	if (os_strcmp(dbus_message_get_signature(message), "ssv")) {
202  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
203  					      NULL);
204  	}
205  
206  	if (dsc->setter == NULL) {
207  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
208  					      "Property is read-only");
209  	}
210  
211  	dbus_message_iter_init(message, &iter);
212  	/* Skip the interface name and the property name */
213  	dbus_message_iter_next(&iter);
214  	dbus_message_iter_next(&iter);
215  
216  	/* Iter will now point to the property's new value */
217  	dbus_error_init(&error);
218  	if (dsc->setter(dsc, &iter, &error, user_data) == TRUE) {
219  		/* Success */
220  		reply = dbus_message_new_method_return(message);
221  	} else {
222  		reply = wpas_dbus_reply_new_from_error(
223  			message, &error, DBUS_ERROR_FAILED,
224  			"Failed to set property");
225  		dbus_error_free(&error);
226  	}
227  
228  	return reply;
229  }
230  
231  
232  static DBusMessage *
properties_get_or_set(DBusMessage * message,DBusMessageIter * iter,char * interface,struct wpa_dbus_object_desc * obj_dsc)233  properties_get_or_set(DBusMessage *message, DBusMessageIter *iter,
234  		      char *interface,
235  		      struct wpa_dbus_object_desc *obj_dsc)
236  {
237  	const struct wpa_dbus_property_desc *property_dsc;
238  	char *property;
239  	const char *method;
240  
241  	method = dbus_message_get_member(message);
242  	property_dsc = obj_dsc->properties;
243  
244  	/* Second argument: property name (DBUS_TYPE_STRING) */
245  	if (!dbus_message_iter_next(iter) ||
246  	    dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
247  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
248  					      NULL);
249  	}
250  	dbus_message_iter_get_basic(iter, &property);
251  
252  	while (property_dsc && property_dsc->dbus_property) {
253  		/* compare property names and
254  		 * interfaces */
255  		if (!os_strncmp(property_dsc->dbus_property, property,
256  				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
257  		    !os_strncmp(property_dsc->dbus_interface, interface,
258  				WPAS_DBUS_INTERFACE_MAX))
259  			break;
260  
261  		property_dsc++;
262  	}
263  	if (property_dsc == NULL || property_dsc->dbus_property == NULL) {
264  		wpa_printf(MSG_DEBUG, "no property handler for %s.%s on %s",
265  			   interface, property,
266  			   dbus_message_get_path(message));
267  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
268  					      "No such property");
269  	}
270  
271  	if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
272  		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) {
273  		wpa_printf(MSG_MSGDUMP, "%s: Get(%s)", __func__, property);
274  		return properties_get(message, property_dsc,
275  				      obj_dsc->user_data);
276  	}
277  
278  	wpa_printf(MSG_MSGDUMP, "%s: Set(%s)", __func__, property);
279  	return properties_set(message, property_dsc, obj_dsc->user_data);
280  }
281  
282  
properties_handler(DBusMessage * message,struct wpa_dbus_object_desc * obj_dsc)283  static DBusMessage * properties_handler(DBusMessage *message,
284  					struct wpa_dbus_object_desc *obj_dsc)
285  {
286  	DBusMessageIter iter;
287  	char *interface;
288  	const char *method;
289  
290  	method = dbus_message_get_member(message);
291  	dbus_message_iter_init(message, &iter);
292  
293  	if (!os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
294  			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
295  	    !os_strncmp(WPA_DBUS_PROPERTIES_SET, method,
296  			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) ||
297  	    !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
298  			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
299  		/* First argument: interface name (DBUS_TYPE_STRING) */
300  		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
301  			return dbus_message_new_error(message,
302  						      DBUS_ERROR_INVALID_ARGS,
303  						      NULL);
304  		}
305  
306  		dbus_message_iter_get_basic(&iter, &interface);
307  
308  		if (!os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
309  				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
310  			/* GetAll */
311  			return properties_get_all(message, interface, obj_dsc);
312  		}
313  		/* Get or Set */
314  		return properties_get_or_set(message, &iter, interface,
315  					     obj_dsc);
316  	}
317  	return dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD,
318  				      NULL);
319  }
320  
321  
msg_method_handler(DBusMessage * message,struct wpa_dbus_object_desc * obj_dsc)322  static DBusMessage * msg_method_handler(DBusMessage *message,
323  					struct wpa_dbus_object_desc *obj_dsc)
324  {
325  	const struct wpa_dbus_method_desc *method_dsc = obj_dsc->methods;
326  	const char *method;
327  	const char *msg_interface;
328  
329  	method = dbus_message_get_member(message);
330  	msg_interface = dbus_message_get_interface(message);
331  
332  	/* try match call to any registered method */
333  	while (method_dsc && method_dsc->dbus_method) {
334  		/* compare method names and interfaces */
335  		if (!os_strncmp(method_dsc->dbus_method, method,
336  				WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
337  		    !os_strncmp(method_dsc->dbus_interface, msg_interface,
338  				WPAS_DBUS_INTERFACE_MAX))
339  			break;
340  
341  		method_dsc++;
342  	}
343  	if (method_dsc == NULL || method_dsc->dbus_method == NULL) {
344  		wpa_printf(MSG_DEBUG, "no method handler for %s.%s on %s",
345  			   msg_interface, method,
346  			   dbus_message_get_path(message));
347  		return dbus_message_new_error(message,
348  					      DBUS_ERROR_UNKNOWN_METHOD, NULL);
349  	}
350  
351  	if (!is_signature_correct(message, method_dsc)) {
352  		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
353  					      NULL);
354  	}
355  
356  	return method_dsc->method_handler(message, obj_dsc->user_data);
357  }
358  
359  
360  /**
361   * message_handler - Handles incoming DBus messages
362   * @connection: DBus connection on which message was received
363   * @message: Received message
364   * @user_data: pointer to description of object to which message was sent
365   * Returns: Returns information whether message was handled or not
366   *
367   * Reads message interface and method name, then checks if they matches one
368   * of the special cases i.e. introspection call or properties get/getall/set
369   * methods and handles it. Else it iterates over registered methods list
370   * and tries to match method's name and interface to those read from message
371   * If appropriate method was found its handler function is called and
372   * response is sent. Otherwise, the DBUS_ERROR_UNKNOWN_METHOD error message
373   * will be sent.
374   */
message_handler(DBusConnection * connection,DBusMessage * message,void * user_data)375  static DBusHandlerResult message_handler(DBusConnection *connection,
376  					 DBusMessage *message, void *user_data)
377  {
378  	struct wpa_dbus_object_desc *obj_dsc = user_data;
379  	const char *method;
380  	const char *path;
381  	const char *msg_interface;
382  	DBusMessage *reply;
383  
384  	/* get method, interface and path the message is addressed to */
385  	method = dbus_message_get_member(message);
386  	path = dbus_message_get_path(message);
387  	msg_interface = dbus_message_get_interface(message);
388  	if (!method || !path || !msg_interface)
389  		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
390  
391  	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s) [%s]",
392  		   msg_interface, method, path,
393  		   dbus_message_get_signature(message));
394  
395  	/* if message is introspection method call */
396  	if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
397  			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) &&
398  	    !os_strncmp(WPA_DBUS_INTROSPECTION_INTERFACE, msg_interface,
399  			WPAS_DBUS_INTERFACE_MAX)) {
400  #ifdef CONFIG_CTRL_IFACE_DBUS_INTRO
401  		reply = wpa_dbus_introspect(message, obj_dsc);
402  #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
403  		reply = dbus_message_new_error(
404  			message, DBUS_ERROR_UNKNOWN_METHOD,
405  			"wpa_supplicant was compiled without introspection support.");
406  #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
407  	} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
408  			     WPAS_DBUS_INTERFACE_MAX)) {
409  		/* if message is properties method call */
410  		reply = properties_handler(message, obj_dsc);
411  	} else {
412  		reply = msg_method_handler(message, obj_dsc);
413  	}
414  
415  	/* If handler succeed returning NULL, reply empty message */
416  	if (!reply)
417  		reply = dbus_message_new_method_return(message);
418  	if (reply) {
419  		if (!dbus_message_get_no_reply(message))
420  			dbus_connection_send(connection, reply, NULL);
421  		dbus_message_unref(reply);
422  	}
423  
424  	wpa_dbus_flush_all_changed_properties(connection);
425  
426  	return DBUS_HANDLER_RESULT_HANDLED;
427  }
428  
429  
430  /**
431   * free_dbus_object_desc - Frees object description data structure
432   * @connection: DBus connection
433   * @obj_dsc: Object description to free
434   *
435   * Frees each of properties, methods and signals description lists and
436   * the object description structure itself.
437   */
free_dbus_object_desc(struct wpa_dbus_object_desc * obj_dsc)438  void free_dbus_object_desc(struct wpa_dbus_object_desc *obj_dsc)
439  {
440  	if (!obj_dsc)
441  		return;
442  
443  	/* free handler's argument */
444  	if (obj_dsc->user_data_free_func)
445  		obj_dsc->user_data_free_func(obj_dsc->user_data);
446  
447  	os_free(obj_dsc->path);
448  	os_free(obj_dsc->prop_changed_flags);
449  	os_free(obj_dsc);
450  }
451  
452  
free_dbus_object_desc_cb(DBusConnection * connection,void * obj_dsc)453  static void free_dbus_object_desc_cb(DBusConnection *connection, void *obj_dsc)
454  {
455  	free_dbus_object_desc(obj_dsc);
456  }
457  
458  
459  /**
460   * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
461   * @application_data: Pointer to application specific data structure
462   * @dbus_path: DBus path to interface object
463   * @dbus_service: DBus service name to register with
464   * @messageHandler: a pointer to function which will handle dbus messages
465   * coming on interface
466   * Returns: 0 on success, -1 on failure
467   *
468   * Initialize the dbus control interface and start receiving commands from
469   * external programs over the bus.
470   */
wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv * iface,char * dbus_path,char * dbus_service,struct wpa_dbus_object_desc * obj_desc)471  int wpa_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface,
472  			     char *dbus_path, char *dbus_service,
473  			     struct wpa_dbus_object_desc *obj_desc)
474  {
475  	DBusError error;
476  	int ret = -1;
477  	DBusObjectPathVTable wpa_vtable = {
478  		&free_dbus_object_desc_cb, &message_handler,
479  		NULL, NULL, NULL, NULL
480  	};
481  
482  	obj_desc->connection = iface->con;
483  	obj_desc->path = os_strdup(dbus_path);
484  
485  	/* Register the message handler for the global dbus interface */
486  	if (!dbus_connection_register_object_path(iface->con, dbus_path,
487  						  &wpa_vtable, obj_desc)) {
488  		wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
489  		return -1;
490  	}
491  
492  	/* Register our service with the message bus */
493  	dbus_error_init(&error);
494  	switch (dbus_bus_request_name(iface->con, dbus_service, 0, &error)) {
495  	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
496  		ret = 0;
497  		break;
498  	case DBUS_REQUEST_NAME_REPLY_EXISTS:
499  	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
500  	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
501  		wpa_printf(MSG_ERROR,
502  			   "dbus: Could not request service name: already registered");
503  		break;
504  	default:
505  		wpa_printf(MSG_ERROR,
506  			   "dbus: Could not request service name: %s %s",
507  			   error.name, error.message);
508  		break;
509  	}
510  	dbus_error_free(&error);
511  
512  	if (ret != 0)
513  		return -1;
514  
515  	wpa_printf(MSG_DEBUG, "Providing DBus service '%s'.", dbus_service);
516  
517  	return 0;
518  }
519  
520  
521  /**
522   * wpa_dbus_register_object_per_iface - Register a new object with dbus
523   * @ctrl_iface: pointer to dbus private data
524   * @path: DBus path to object
525   * @ifname: interface name
526   * @obj_desc: description of object's methods, signals and properties
527   * Returns: 0 on success, -1 on error
528   *
529   * Registers a new interface with dbus and assigns it a dbus object path.
530   */
wpa_dbus_register_object_per_iface(struct wpas_dbus_priv * ctrl_iface,const char * path,const char * ifname,struct wpa_dbus_object_desc * obj_desc)531  int wpa_dbus_register_object_per_iface(struct wpas_dbus_priv *ctrl_iface,
532  				       const char *path, const char *ifname,
533  				       struct wpa_dbus_object_desc *obj_desc)
534  {
535  	DBusConnection *con;
536  	DBusError error;
537  	DBusObjectPathVTable vtable = {
538  		&free_dbus_object_desc_cb, &message_handler,
539  		NULL, NULL, NULL, NULL
540  	};
541  
542  	/* Do nothing if the control interface is not turned on */
543  	if (ctrl_iface == NULL)
544  		return 0;
545  
546  	con = ctrl_iface->con;
547  	obj_desc->connection = con;
548  	obj_desc->path = os_strdup(path);
549  
550  	dbus_error_init(&error);
551  	/* Register the message handler for the interface functions */
552  	if (!dbus_connection_try_register_object_path(con, path, &vtable,
553  						      obj_desc, &error)) {
554  		if (os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
555  			wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
556  		} else {
557  			wpa_printf(MSG_ERROR,
558  				   "dbus: Could not set up message handler for interface %s object %s (error: %s message: %s)",
559  				   ifname, path, error.name, error.message);
560  		}
561  		dbus_error_free(&error);
562  		return -1;
563  	}
564  
565  	dbus_error_free(&error);
566  	return 0;
567  }
568  
569  
570  static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx);
571  
572  
573  /**
574   * wpa_dbus_unregister_object_per_iface - Unregisters DBus object
575   * @ctrl_iface: Pointer to dbus private data
576   * @path: DBus path to object which will be unregistered
577   * Returns: Zero on success and -1 on failure
578   *
579   * Unregisters DBus object given by its path
580   */
wpa_dbus_unregister_object_per_iface(struct wpas_dbus_priv * ctrl_iface,const char * path)581  int wpa_dbus_unregister_object_per_iface(
582  	struct wpas_dbus_priv *ctrl_iface, const char *path)
583  {
584  	DBusConnection *con = ctrl_iface->con;
585  	struct wpa_dbus_object_desc *obj_desc = NULL;
586  
587  	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
588  	if (!obj_desc) {
589  		wpa_printf(MSG_ERROR,
590  			   "dbus: %s: Could not obtain object's private data: %s",
591  			   __func__, path);
592  		return 0;
593  	}
594  
595  	eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
596  
597  	if (!dbus_connection_unregister_object_path(con, path))
598  		return -1;
599  
600  	return 0;
601  }
602  
603  
put_changed_properties(const struct wpa_dbus_object_desc * obj_dsc,const char * interface,DBusMessageIter * dict_iter,int clear_changed)604  static dbus_bool_t put_changed_properties(
605  	const struct wpa_dbus_object_desc *obj_dsc, const char *interface,
606  	DBusMessageIter *dict_iter, int clear_changed)
607  {
608  	DBusMessageIter entry_iter;
609  	const struct wpa_dbus_property_desc *dsc;
610  	int i;
611  	DBusError error;
612  
613  	for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property;
614  	     dsc++, i++) {
615  		if (obj_dsc->prop_changed_flags == NULL ||
616  		    !obj_dsc->prop_changed_flags[i])
617  			continue;
618  		if (os_strcmp(dsc->dbus_interface, interface) != 0)
619  			continue;
620  		if (clear_changed)
621  			obj_dsc->prop_changed_flags[i] = 0;
622  
623  		if (!dbus_message_iter_open_container(dict_iter,
624  						      DBUS_TYPE_DICT_ENTRY,
625  						      NULL, &entry_iter) ||
626  		    !dbus_message_iter_append_basic(&entry_iter,
627  						    DBUS_TYPE_STRING,
628  						    &dsc->dbus_property))
629  			return FALSE;
630  
631  		dbus_error_init(&error);
632  		if (!dsc->getter(dsc, &entry_iter, &error, obj_dsc->user_data))
633  		{
634  			if (dbus_error_is_set(&error)) {
635  				wpa_printf(MSG_ERROR,
636  					   "dbus: %s: Cannot get new value of property %s: (%s) %s",
637  					   __func__, dsc->dbus_property,
638  					   error.name, error.message);
639  			} else {
640  				wpa_printf(MSG_ERROR,
641  					   "dbus: %s: Cannot get new value of property %s",
642  					   __func__, dsc->dbus_property);
643  			}
644  			dbus_error_free(&error);
645  			return FALSE;
646  		}
647  
648  		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
649  			return FALSE;
650  	}
651  
652  	return TRUE;
653  }
654  
655  
do_send_prop_changed_signal(DBusConnection * con,const char * path,const char * interface,const struct wpa_dbus_object_desc * obj_dsc)656  static void do_send_prop_changed_signal(
657  	DBusConnection *con, const char *path, const char *interface,
658  	const struct wpa_dbus_object_desc *obj_dsc)
659  {
660  	DBusMessage *msg;
661  	DBusMessageIter signal_iter, dict_iter;
662  
663  	msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES,
664  				      "PropertiesChanged");
665  	if (msg == NULL)
666  		return;
667  
668  	dbus_message_iter_init_append(msg, &signal_iter);
669  
670  	if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
671  					    &interface) ||
672  	    /* Changed properties dict */
673  	    !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
674  					      "{sv}", &dict_iter))
675  		goto fail;
676  	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0)) {
677  		dbus_message_iter_close_container(&signal_iter, &dict_iter);
678  		goto fail;
679  	}
680  	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter) ||
681  	    /* Invalidated properties array (empty) */
682  	    !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
683  					      "s", &dict_iter) ||
684  	    !dbus_message_iter_close_container(&signal_iter, &dict_iter))
685  		goto fail;
686  
687  	dbus_connection_send(con, msg, NULL);
688  
689  out:
690  	dbus_message_unref(msg);
691  	return;
692  fail:
693  	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", __func__);
694  	goto out;
695  }
696  
697  
do_send_deprecated_prop_changed_signal(DBusConnection * con,const char * path,const char * interface,const struct wpa_dbus_object_desc * obj_dsc)698  static void do_send_deprecated_prop_changed_signal(
699  	DBusConnection *con, const char *path, const char *interface,
700  	const struct wpa_dbus_object_desc *obj_dsc)
701  {
702  	DBusMessage *msg;
703  	DBusMessageIter signal_iter, dict_iter;
704  
705  	msg = dbus_message_new_signal(path, interface, "PropertiesChanged");
706  	if (msg == NULL)
707  		return;
708  
709  	dbus_message_iter_init_append(msg, &signal_iter);
710  
711  	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
712  					      "{sv}", &dict_iter))
713  		goto fail;
714  	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1)) {
715  		dbus_message_iter_close_container(&signal_iter, &dict_iter);
716  		goto fail;
717  	}
718  	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
719  		goto fail;
720  
721  	dbus_connection_send(con, msg, NULL);
722  
723  out:
724  	dbus_message_unref(msg);
725  	return;
726  fail:
727  	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal", __func__);
728  	goto out;
729  }
730  
731  
send_prop_changed_signal(DBusConnection * con,const char * path,const char * interface,const struct wpa_dbus_object_desc * obj_dsc)732  static void send_prop_changed_signal(
733  	DBusConnection *con, const char *path, const char *interface,
734  	const struct wpa_dbus_object_desc *obj_dsc)
735  {
736  	/*
737  	 * First, send property change notification on the standardized
738  	 * org.freedesktop.DBus.Properties interface. This call will not
739  	 * clear the property change bits, so that they are preserved for
740  	 * the call that follows.
741  	 */
742  	do_send_prop_changed_signal(con, path, interface, obj_dsc);
743  
744  	/*
745  	 * Now send PropertiesChanged on our own interface for backwards
746  	 * compatibility. This is deprecated and will be removed in a future
747  	 * release.
748  	 */
749  	do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc);
750  
751  	/* Property change bits have now been cleared. */
752  }
753  
754  
flush_object_timeout_handler(void * eloop_ctx,void * timeout_ctx)755  static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
756  {
757  	DBusConnection *con = eloop_ctx;
758  	struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
759  
760  	wpa_printf(MSG_MSGDUMP,
761  		   "dbus: %s: Timeout - sending changed properties of object %s",
762  		   __func__, obj_desc->path);
763  	wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
764  }
765  
766  
recursive_flush_changed_properties(DBusConnection * con,const char * path)767  static void recursive_flush_changed_properties(DBusConnection *con,
768  					       const char *path)
769  {
770  	char **objects = NULL;
771  	char subobj_path[WPAS_DBUS_OBJECT_PATH_MAX];
772  	int i;
773  
774  	wpa_dbus_flush_object_changed_properties(con, path);
775  
776  	if (!dbus_connection_list_registered(con, path, &objects))
777  		goto out;
778  
779  	for (i = 0; objects[i]; i++) {
780  		os_snprintf(subobj_path, WPAS_DBUS_OBJECT_PATH_MAX,
781  			    "%s/%s", path, objects[i]);
782  		recursive_flush_changed_properties(con, subobj_path);
783  	}
784  
785  out:
786  	dbus_free_string_array(objects);
787  }
788  
789  
790  /**
791   * wpa_dbus_flush_all_changed_properties - Send all PropertiesChanged signals
792   * @con: DBus connection
793   *
794   * Traverses through all registered objects and sends PropertiesChanged for
795   * each properties.
796   */
wpa_dbus_flush_all_changed_properties(DBusConnection * con)797  void wpa_dbus_flush_all_changed_properties(DBusConnection *con)
798  {
799  	recursive_flush_changed_properties(con, WPAS_DBUS_NEW_PATH);
800  }
801  
802  
803  /**
804   * wpa_dbus_flush_object_changed_properties - Send PropertiesChanged for object
805   * @con: DBus connection
806   * @path: path to a DBus object for which PropertiesChanged will be sent.
807   *
808   * Iterates over all properties registered with object and for each interface
809   * containing properties marked as changed, sends a PropertiesChanged signal
810   * containing names and new values of properties that have changed.
811   *
812   * You need to call this function after wpa_dbus_mark_property_changed()
813   * if you want to send PropertiesChanged signal immediately (i.e., without
814   * waiting timeout to expire). PropertiesChanged signal for an object is sent
815   * automatically short time after first marking property as changed. All
816   * PropertiesChanged signals are sent automatically after responding on DBus
817   * message, so if you marked a property changed as a result of DBus call
818   * (e.g., param setter), you usually do not need to call this function.
819   */
wpa_dbus_flush_object_changed_properties(DBusConnection * con,const char * path)820  void wpa_dbus_flush_object_changed_properties(DBusConnection *con,
821  					      const char *path)
822  {
823  	struct wpa_dbus_object_desc *obj_desc = NULL;
824  	const struct wpa_dbus_property_desc *dsc;
825  	int i;
826  
827  	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
828  	if (!obj_desc)
829  		return;
830  	eloop_cancel_timeout(flush_object_timeout_handler, con, obj_desc);
831  
832  	for (dsc = obj_desc->properties, i = 0; dsc && dsc->dbus_property;
833  	     dsc++, i++) {
834  		if (obj_desc->prop_changed_flags == NULL ||
835  		    !obj_desc->prop_changed_flags[i])
836  			continue;
837  		send_prop_changed_signal(con, path, dsc->dbus_interface,
838  					 obj_desc);
839  	}
840  }
841  
842  
843  #define WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT 5000
844  
845  
846  /**
847   * wpa_dbus_mark_property_changed - Mark a property as changed and
848   * @iface: dbus priv struct
849   * @path: path to DBus object which property has changed
850   * @interface: interface containing changed property
851   * @property: property name which has changed
852   *
853   * Iterates over all properties registered with an object and marks the one
854   * given in parameters as changed. All parameters registered for an object
855   * within a single interface will be aggregated together and sent in one
856   * PropertiesChanged signal when function
857   * wpa_dbus_flush_object_changed_properties() is called.
858   */
wpa_dbus_mark_property_changed(struct wpas_dbus_priv * iface,const char * path,const char * interface,const char * property)859  void wpa_dbus_mark_property_changed(struct wpas_dbus_priv *iface,
860  				    const char *path, const char *interface,
861  				    const char *property)
862  {
863  	struct wpa_dbus_object_desc *obj_desc = NULL;
864  	const struct wpa_dbus_property_desc *dsc;
865  	int i = 0;
866  
867  	if (iface == NULL)
868  		return;
869  
870  	dbus_connection_get_object_path_data(iface->con, path,
871  					     (void **) &obj_desc);
872  	if (!obj_desc) {
873  		wpa_printf(MSG_ERROR,
874  			   "dbus: wpa_dbus_property_changed: could not obtain object's private data: %s",
875  			   path);
876  		return;
877  	}
878  
879  	for (dsc = obj_desc->properties; dsc && dsc->dbus_property; dsc++, i++)
880  		if (os_strcmp(property, dsc->dbus_property) == 0 &&
881  		    os_strcmp(interface, dsc->dbus_interface) == 0) {
882  			if (obj_desc->prop_changed_flags)
883  				obj_desc->prop_changed_flags[i] = 1;
884  			break;
885  		}
886  
887  	if (!dsc || !dsc->dbus_property) {
888  		wpa_printf(MSG_ERROR,
889  			   "dbus: wpa_dbus_property_changed: no property %s in object %s",
890  			   property, path);
891  		return;
892  	}
893  
894  	if (!eloop_is_timeout_registered(flush_object_timeout_handler,
895  					 iface->con, obj_desc)) {
896  		eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
897  				       flush_object_timeout_handler,
898  				       iface->con, obj_desc);
899  	}
900  }
901  
902  
903  /**
904   * wpa_dbus_get_object_properties - Put object's properties into dictionary
905   * @iface: dbus priv struct
906   * @path: path to DBus object which properties will be obtained
907   * @interface: interface name which properties will be obtained
908   * @iter: DBus message iter at which to append property dictionary.
909   *
910   * Iterates over all properties registered with object and execute getters
911   * of those, which are readable and which interface matches interface
912   * specified as argument. Obtained properties values are stored in
913   * dict_iter dictionary.
914   */
wpa_dbus_get_object_properties(struct wpas_dbus_priv * iface,const char * path,const char * interface,DBusMessageIter * iter)915  dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
916  					   const char *path,
917  					   const char *interface,
918  					   DBusMessageIter *iter)
919  {
920  	struct wpa_dbus_object_desc *obj_desc = NULL;
921  	DBusMessageIter dict_iter;
922  	DBusError error;
923  
924  	dbus_connection_get_object_path_data(iface->con, path,
925  					     (void **) &obj_desc);
926  	if (!obj_desc) {
927  		wpa_printf(MSG_ERROR,
928  			   "dbus: %s: could not obtain object's private data: %s",
929  			   __func__, path);
930  		return FALSE;
931  	}
932  
933  	if (!wpa_dbus_dict_open_write(iter, &dict_iter)) {
934  		wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict",
935  			   __func__);
936  		return FALSE;
937  	}
938  
939  	dbus_error_init(&error);
940  	if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
941  				       interface, obj_desc->user_data,
942  				       &error)) {
943  		wpa_printf(MSG_ERROR,
944  			   "dbus: %s: failed to get object properties: (%s) %s",
945  			   __func__,
946  			   dbus_error_is_set(&error) ? error.name : "none",
947  			   dbus_error_is_set(&error) ? error.message : "none");
948  		dbus_error_free(&error);
949  		wpa_dbus_dict_close_write(iter, &dict_iter);
950  		return FALSE;
951  	}
952  
953  	return wpa_dbus_dict_close_write(iter, &dict_iter);
954  }
955  
956  /**
957   * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
958   * @path: The dbus object path
959   * @sep: Separating part (e.g., "Networks" or "PersistentGroups")
960   * @item: (out) The part following the specified separator, if any
961   * Returns: The object path of the interface this path refers to
962   *
963   * For a given object path, decomposes the object path into object id and
964   * requested part, if those parts exist. The caller is responsible for freeing
965   * the returned value. The *item pointer points to that allocated value and must
966   * not be freed separately.
967   *
968   * As an example, path = "/fi/w1/wpa_supplicant1/Interfaces/1/Networks/0" and
969   * sep = "Networks" would result in "/fi/w1/wpa_supplicant1/Interfaces/1"
970   * getting returned and *items set to point to "0".
971   */
wpas_dbus_new_decompose_object_path(const char * path,const char * sep,char ** item)972  char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
973  					   char **item)
974  {
975  	const unsigned int dev_path_prefix_len =
976  		os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
977  	char *obj_path_only;
978  	char *pos;
979  	size_t sep_len;
980  
981  	*item = NULL;
982  
983  	/* Verify that this starts with our interface prefix */
984  	if (os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
985  		       dev_path_prefix_len) != 0)
986  		return NULL; /* not our path */
987  
988  	/* Ensure there's something at the end of the path */
989  	if ((path + dev_path_prefix_len)[0] == '\0')
990  		return NULL;
991  
992  	obj_path_only = os_strdup(path);
993  	if (obj_path_only == NULL)
994  		return NULL;
995  
996  	pos = obj_path_only + dev_path_prefix_len;
997  	pos = os_strchr(pos, '/');
998  	if (pos == NULL)
999  		return obj_path_only; /* no next item on the path */
1000  
1001  	 /* Separate network interface prefix from the path */
1002  	*pos++ = '\0';
1003  
1004  	sep_len = os_strlen(sep);
1005  	if (os_strncmp(pos, sep, sep_len) != 0 || pos[sep_len] != '/')
1006  		return obj_path_only; /* no match */
1007  
1008  	 /* return a pointer to the requested item */
1009  	*item = pos + sep_len + 1;
1010  	return obj_path_only;
1011  }
1012  
1013  
1014  /**
1015   * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
1016   *   dbus error structure
1017   * @message: The original request message for which the error is a reply
1018   * @error: The error containing a name and a descriptive error cause
1019   * @fallback_name: A generic error name if @error was not set
1020   * @fallback_string: A generic error string if @error was not set
1021   * Returns: A new D-Bus error message
1022   *
1023   * Given a DBusMessage structure, creates a new D-Bus error message using
1024   * the error name and string contained in that structure.
1025   */
wpas_dbus_reply_new_from_error(DBusMessage * message,DBusError * error,const char * fallback_name,const char * fallback_string)1026  DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message,
1027  					     DBusError *error,
1028  					     const char *fallback_name,
1029  					     const char *fallback_string)
1030  {
1031  	if (error && error->name && error->message) {
1032  		return dbus_message_new_error(message, error->name,
1033  					      error->message);
1034  	}
1035  	if (fallback_name && fallback_string) {
1036  		return dbus_message_new_error(message, fallback_name,
1037  					      fallback_string);
1038  	}
1039  	return NULL;
1040  }
1041  
1042  
guard_interval_to_double(enum guard_interval value)1043  static double guard_interval_to_double(enum guard_interval value)
1044  {
1045  	switch (value) {
1046  	case GUARD_INTERVAL_0_4:
1047  		return 0.4;
1048  	case GUARD_INTERVAL_0_8:
1049  		return 0.8;
1050  	case GUARD_INTERVAL_1_6:
1051  		return 1.6;
1052  	case GUARD_INTERVAL_3_2:
1053  		return 3.2;
1054  	default:
1055  		return 0;
1056  	}
1057  }
1058  
1059  
1060  /**
1061   * wpas_dbus_new_from_signal_information - Adds a wpa_signal_info
1062   * to a DBusMessage.
1063   * @msg: Pointer to message to append fields to
1064   * @si: Pointer to wpa_signal_info to add to the message
1065   * Returns: 0 on success, otherwise, an errorcode
1066   *
1067   * Adds all the pertinent fields from a wpa_signal_info to a DBusMessage.
1068   * The same logic is useful in both responding to signal_poll calls, and
1069   * sending signal_change signals.
1070   */
wpas_dbus_new_from_signal_information(DBusMessageIter * iter,struct wpa_signal_info * si)1071  int wpas_dbus_new_from_signal_information(DBusMessageIter *iter,
1072  					  struct wpa_signal_info *si)
1073  {
1074  	DBusMessageIter iter_dict, variant_iter;
1075  
1076  	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
1077  					      "a{sv}", &variant_iter) ||
1078  	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
1079  	    !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
1080  					si->data.signal) ||
1081  	    !wpa_dbus_dict_append_uint32(&iter_dict, "linkspeed",
1082  					si->data.current_tx_rate / 1000) ||
1083  	    !wpa_dbus_dict_append_int32(&iter_dict, "noise",
1084  					si->current_noise) ||
1085  	    !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
1086  					 si->frequency) ||
1087  	    (si->chanwidth != CHAN_WIDTH_UNKNOWN &&
1088  	     !wpa_dbus_dict_append_string(
1089  		     &iter_dict, "width",
1090  		     channel_width_to_string(si->chanwidth))) ||
1091  	    (si->center_frq1 > 0 && si->center_frq2 > 0 &&
1092  	     (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
1093  					  si->center_frq1) ||
1094  	      !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
1095  					  si->center_frq2))) ||
1096  	    (si->data.avg_signal &&
1097  	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
1098  					 si->data.avg_signal)) ||
1099  	    (si->data.rx_bytes &&
1100  	     !wpa_dbus_dict_append_uint64(&iter_dict, "rx-bytes",
1101  					  si->data.rx_bytes)) ||
1102  	    (si->data.tx_bytes &&
1103  	     !wpa_dbus_dict_append_uint64(&iter_dict, "tx-bytes",
1104  					  si->data.tx_bytes)) ||
1105  	    (si->data.rx_packets &&
1106  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-packets",
1107  					  si->data.rx_packets)) ||
1108  	    (si->data.tx_packets &&
1109  	     !wpa_dbus_dict_append_uint32(&iter_dict, "tx-packets",
1110  					  si->data.tx_packets)) ||
1111  	    (si->data.beacons_count &&
1112  	     !wpa_dbus_dict_append_uint64(&iter_dict, "beacons",
1113  					  si->data.beacons_count)) ||
1114  	    (si->data.current_rx_rate &&
1115  	     !wpa_dbus_dict_append_uint32(&iter_dict, "linkrxspeed",
1116  					  si->data.current_rx_rate)) ||
1117  	    (si->data.current_rx_rate &&
1118  	     !wpa_dbus_dict_append_uint32(&iter_dict, "linktxspeed",
1119  					  si->data.current_tx_rate)) ||
1120  	    (si->data.inactive_msec &&
1121  	     !wpa_dbus_dict_append_uint32(&iter_dict, "inactive-time",
1122  					 si->data.inactive_msec)) ||
1123  	    (si->data.tx_retry_failed &&
1124  	     !wpa_dbus_dict_append_uint32(&iter_dict, "retries-failed",
1125  					  si->data.tx_retry_failed)) ||
1126  	    (si->data.tx_retry_count &&
1127  	     !wpa_dbus_dict_append_uint32(&iter_dict, "retries",
1128  					  si->data.tx_retry_count)) ||
1129  	    (si->data.last_ack_rssi &&
1130  	     !wpa_dbus_dict_append_int32(&iter_dict, "last-ack-rssi",
1131  					 si->data.last_ack_rssi)) ||
1132  	    (si->data.fcs_error_count &&
1133  	     !wpa_dbus_dict_append_uint32(&iter_dict, "fcs-errors",
1134  					  si->data.fcs_error_count)) ||
1135  	    (si->data.beacon_loss_count &&
1136  	     !wpa_dbus_dict_append_uint32(&iter_dict, "beacon-losses",
1137  					  si->data.beacon_loss_count)) ||
1138  	    (si->data.expected_throughput &&
1139  	     !wpa_dbus_dict_append_uint32(&iter_dict, "expected-throughput",
1140  					  si->data.expected_throughput)) ||
1141  	    (si->data.rx_drop_misc &&
1142  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-drop-misc",
1143  					  si->data.rx_drop_misc)) ||
1144  	    (si->data.rx_mpdus &&
1145  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-mpdus",
1146  					  si->data.rx_mpdus)) ||
1147  	    (si->data.rx_hemcs &&
1148  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-he-mcs",
1149  					  si->data.rx_hemcs)) ||
1150  	    (si->data.tx_hemcs &&
1151  	     !wpa_dbus_dict_append_uint32(&iter_dict, "tx-he-mcs",
1152  					  si->data.tx_hemcs)) ||
1153  	    (si->data.rx_vhtmcs &&
1154  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-vht-mcs",
1155  					  si->data.rx_vhtmcs)) ||
1156  	    (si->data.tx_vhtmcs &&
1157  	     !wpa_dbus_dict_append_uint32(&iter_dict, "tx-vht-mcs",
1158  					  si->data.tx_vhtmcs)) ||
1159  	    (si->data.rx_mcs &&
1160  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-mcs",
1161  					  si->data.rx_mcs)) ||
1162  	    (si->data.tx_mcs &&
1163  	     !wpa_dbus_dict_append_uint32(&iter_dict, "tx-mcs",
1164  					  si->data.tx_mcs)) ||
1165  	    (si->data.rx_he_nss &&
1166  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-he-nss",
1167  					  si->data.rx_he_nss)) ||
1168  	    (si->data.tx_he_nss &&
1169  	     !wpa_dbus_dict_append_uint32(&iter_dict, "tx-he-nss",
1170  					  si->data.tx_he_nss)) ||
1171  	    (si->data.rx_vht_nss &&
1172  	     !wpa_dbus_dict_append_uint32(&iter_dict, "rx-vht-nss",
1173  					  si->data.rx_vht_nss)) ||
1174  	    (si->data.tx_vht_nss &&
1175  	     !wpa_dbus_dict_append_uint32(&iter_dict, "tx-vht-nss",
1176  					  si->data.tx_vht_nss)) ||
1177  	    (si->data.avg_beacon_signal &&
1178  	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-beacon-rssi",
1179  					 si->data.avg_beacon_signal)) ||
1180  	    (si->data.avg_ack_signal &&
1181  	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-ack-rssi",
1182  					 si->data.avg_ack_signal)) ||
1183  	    (si->data.rx_guard_interval &&
1184  	     !wpa_dbus_dict_append_double(
1185  		     &iter_dict, "rx-guard-interval",
1186  		     guard_interval_to_double(si->data.rx_guard_interval))) ||
1187  	    (si->data.tx_guard_interval &&
1188  	     !wpa_dbus_dict_append_double(
1189  		     &iter_dict, "tx-guard-interval",
1190  		     guard_interval_to_double(si->data.tx_guard_interval))) ||
1191  	    ((si->data.flags & STA_DRV_DATA_RX_HE_DCM) &&
1192  	     !wpa_dbus_dict_append_bool(&iter_dict, "rx-dcm",
1193  					si->data.rx_dcm)) ||
1194  	    ((si->data.flags & STA_DRV_DATA_TX_HE_DCM) &&
1195  	     !wpa_dbus_dict_append_bool(&iter_dict, "tx-dcm",
1196  					si->data.tx_dcm)) ||
1197  	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
1198  	    !dbus_message_iter_close_container(iter, &variant_iter))
1199  		return -ENOMEM;
1200  
1201  	return 0;
1202  }
1203