]>
Commit | Line | Data |
---|---|---|
04551ee6 | 1 | /* |
ce4f7fdb | 2 | * wpa_supplicant - D-Bus introspection |
04551ee6 JM |
3 | * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. |
4 | * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com> | |
ce4f7fdb | 5 | * Copyright (c) 2010, Jouni Malinen <j@w1.fi> |
04551ee6 | 6 | * |
c5a3cebf JM |
7 | * This software may be distributed under the terms of the BSD license. |
8 | * See README for more details. | |
04551ee6 JM |
9 | */ |
10 | ||
11 | #include "utils/includes.h" | |
04551ee6 JM |
12 | |
13 | #include "utils/common.h" | |
ce4f7fdb JM |
14 | #include "utils/list.h" |
15 | #include "utils/wpabuf.h" | |
04551ee6 JM |
16 | #include "dbus_common_i.h" |
17 | #include "dbus_new_helpers.h" | |
18 | ||
19 | ||
20 | struct interfaces { | |
ce4f7fdb | 21 | struct dl_list list; |
04551ee6 | 22 | char *dbus_interface; |
ce4f7fdb | 23 | struct wpabuf *xml; |
04551ee6 JM |
24 | }; |
25 | ||
21e338a8 | 26 | |
d316584c JM |
27 | static struct interfaces * add_interface(struct dl_list *list, |
28 | const char *dbus_interface) | |
ce4f7fdb JM |
29 | { |
30 | struct interfaces *iface; | |
31 | ||
32 | dl_list_for_each(iface, list, struct interfaces, list) { | |
33 | if (os_strcmp(iface->dbus_interface, dbus_interface) == 0) | |
d316584c | 34 | return iface; /* already in the list */ |
ce4f7fdb JM |
35 | } |
36 | ||
37 | iface = os_zalloc(sizeof(struct interfaces)); | |
38 | if (!iface) | |
d316584c | 39 | return NULL; |
dacf6058 | 40 | iface->dbus_interface = os_strdup(dbus_interface); |
e50c50d5 | 41 | iface->xml = wpabuf_alloc(15000); |
dacf6058 JM |
42 | if (iface->dbus_interface == NULL || iface->xml == NULL) { |
43 | os_free(iface->dbus_interface); | |
44 | wpabuf_free(iface->xml); | |
ce4f7fdb | 45 | os_free(iface); |
d316584c | 46 | return NULL; |
ce4f7fdb JM |
47 | } |
48 | wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface); | |
49 | dl_list_add_tail(list, &iface->list); | |
d316584c JM |
50 | return iface; |
51 | } | |
52 | ||
53 | ||
54 | static void add_arg(struct wpabuf *xml, const char *name, const char *type, | |
55 | const char *direction) | |
56 | { | |
57 | wpabuf_printf(xml, "<arg name=\"%s\"", name); | |
58 | if (type) | |
59 | wpabuf_printf(xml, " type=\"%s\"", type); | |
60 | if (direction) | |
61 | wpabuf_printf(xml, " direction=\"%s\"", direction); | |
62 | wpabuf_put_str(xml, "/>"); | |
63 | } | |
64 | ||
65 | ||
e90bd80c JM |
66 | static void add_entry(struct wpabuf *xml, const char *type, const char *name, |
67 | const struct wpa_dbus_argument *args, int include_dir) | |
d316584c | 68 | { |
e90bd80c JM |
69 | const struct wpa_dbus_argument *arg; |
70 | ||
71 | if (args == NULL || args->name == NULL) { | |
d316584c JM |
72 | wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name); |
73 | return; | |
74 | } | |
75 | wpabuf_printf(xml, "<%s name=\"%s\">", type, name); | |
e90bd80c | 76 | for (arg = args; arg && arg->name; arg++) { |
d316584c JM |
77 | add_arg(xml, arg->name, arg->type, |
78 | include_dir ? (arg->dir == ARG_IN ? "in" : "out") : | |
79 | NULL); | |
80 | } | |
81 | wpabuf_printf(xml, "</%s>", type); | |
82 | } | |
83 | ||
84 | ||
85 | static void add_property(struct wpabuf *xml, | |
e90bd80c | 86 | const struct wpa_dbus_property_desc *dsc) |
d316584c | 87 | { |
33206664 JM |
88 | wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" " |
89 | "access=\"%s%s\"/>", | |
d316584c | 90 | dsc->dbus_property, dsc->type, |
33206664 JM |
91 | dsc->getter ? "read" : "", |
92 | dsc->setter ? "write" : ""); | |
ce4f7fdb JM |
93 | } |
94 | ||
95 | ||
e90bd80c JM |
96 | static void extract_interfaces_methods( |
97 | struct dl_list *list, const struct wpa_dbus_method_desc *methods) | |
04551ee6 | 98 | { |
e90bd80c | 99 | const struct wpa_dbus_method_desc *dsc; |
d316584c | 100 | struct interfaces *iface; |
38279bdb | 101 | |
e90bd80c | 102 | for (dsc = methods; dsc && dsc->dbus_method; dsc++) { |
d316584c JM |
103 | iface = add_interface(list, dsc->dbus_interface); |
104 | if (iface) | |
105 | add_entry(iface->xml, "method", dsc->dbus_method, | |
e90bd80c | 106 | dsc->args, 1); |
d316584c | 107 | } |
ce4f7fdb | 108 | } |
04551ee6 | 109 | |
04551ee6 | 110 | |
e90bd80c JM |
111 | static void extract_interfaces_signals( |
112 | struct dl_list *list, const struct wpa_dbus_signal_desc *signals) | |
ce4f7fdb | 113 | { |
e90bd80c | 114 | const struct wpa_dbus_signal_desc *dsc; |
d316584c | 115 | struct interfaces *iface; |
38279bdb | 116 | |
e90bd80c | 117 | for (dsc = signals; dsc && dsc->dbus_signal; dsc++) { |
d316584c JM |
118 | iface = add_interface(list, dsc->dbus_interface); |
119 | if (iface) | |
120 | add_entry(iface->xml, "signal", dsc->dbus_signal, | |
e90bd80c | 121 | dsc->args, 0); |
d316584c | 122 | } |
ce4f7fdb JM |
123 | } |
124 | ||
125 | ||
126 | static void extract_interfaces_properties( | |
e90bd80c | 127 | struct dl_list *list, const struct wpa_dbus_property_desc *properties) |
ce4f7fdb | 128 | { |
e90bd80c | 129 | const struct wpa_dbus_property_desc *dsc; |
d316584c | 130 | struct interfaces *iface; |
38279bdb | 131 | |
e90bd80c | 132 | for (dsc = properties; dsc && dsc->dbus_property; dsc++) { |
d316584c JM |
133 | iface = add_interface(list, dsc->dbus_interface); |
134 | if (iface) | |
135 | add_property(iface->xml, dsc); | |
136 | } | |
ce4f7fdb JM |
137 | } |
138 | ||
139 | ||
140 | /** | |
141 | * extract_interfaces - Extract interfaces from methods, signals and props | |
142 | * @list: Interface list to be filled | |
143 | * @obj_dsc: Description of object from which interfaces will be extracted | |
144 | * | |
145 | * Iterates over all methods, signals, and properties registered with an | |
146 | * object and collects all declared DBus interfaces and create interfaces' | |
147 | * node in XML root node for each. Returned list elements contain interface | |
148 | * name and XML node of corresponding interface. | |
149 | */ | |
150 | static void extract_interfaces(struct dl_list *list, | |
151 | struct wpa_dbus_object_desc *obj_dsc) | |
152 | { | |
153 | extract_interfaces_methods(list, obj_dsc->methods); | |
154 | extract_interfaces_signals(list, obj_dsc->signals); | |
155 | extract_interfaces_properties(list, obj_dsc->properties); | |
156 | } | |
157 | ||
04551ee6 | 158 | |
ce4f7fdb JM |
159 | static void add_interfaces(struct dl_list *list, struct wpabuf *xml) |
160 | { | |
161 | struct interfaces *iface, *n; | |
38279bdb | 162 | |
ce4f7fdb | 163 | dl_list_for_each_safe(iface, n, list, struct interfaces, list) { |
d316584c JM |
164 | if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) { |
165 | wpabuf_put_buf(xml, iface->xml); | |
166 | wpabuf_put_str(xml, "</interface>"); | |
6fc74e51 | 167 | } else { |
38279bdb JM |
168 | wpa_printf(MSG_DEBUG, |
169 | "dbus: Not enough room for add_interfaces inspect data: tailroom %u, add %u", | |
6fc74e51 JM |
170 | (unsigned int) wpabuf_tailroom(xml), |
171 | (unsigned int) wpabuf_len(iface->xml)); | |
d316584c | 172 | } |
ce4f7fdb JM |
173 | dl_list_del(&iface->list); |
174 | wpabuf_free(iface->xml); | |
175 | os_free(iface->dbus_interface); | |
176 | os_free(iface); | |
04551ee6 | 177 | } |
21e338a8 JM |
178 | } |
179 | ||
180 | ||
ce4f7fdb JM |
181 | static void add_child_nodes(struct wpabuf *xml, DBusConnection *con, |
182 | const char *path) | |
183 | { | |
184 | char **children; | |
185 | int i; | |
186 | ||
187 | /* add child nodes to introspection tree */ | |
188 | dbus_connection_list_registered(con, path, &children); | |
189 | for (i = 0; children[i]; i++) | |
190 | wpabuf_printf(xml, "<node name=\"%s\"/>", children[i]); | |
191 | dbus_free_string_array(children); | |
192 | } | |
193 | ||
194 | ||
ce4f7fdb JM |
195 | static void add_introspectable_interface(struct wpabuf *xml) |
196 | { | |
197 | wpabuf_printf(xml, "<interface name=\"%s\">" | |
198 | "<method name=\"%s\">" | |
199 | "<arg name=\"data\" type=\"s\" direction=\"out\"/>" | |
200 | "</method>" | |
201 | "</interface>", | |
202 | WPA_DBUS_INTROSPECTION_INTERFACE, | |
203 | WPA_DBUS_INTROSPECTION_METHOD); | |
204 | } | |
205 | ||
04551ee6 | 206 | |
ce4f7fdb JM |
207 | static void add_properties_interface(struct wpabuf *xml) |
208 | { | |
209 | wpabuf_printf(xml, "<interface name=\"%s\">", | |
210 | WPA_DBUS_PROPERTIES_INTERFACE); | |
211 | ||
212 | wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GET); | |
213 | add_arg(xml, "interface", "s", "in"); | |
214 | add_arg(xml, "propname", "s", "in"); | |
215 | add_arg(xml, "value", "v", "out"); | |
216 | wpabuf_put_str(xml, "</method>"); | |
217 | ||
218 | wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_GETALL); | |
219 | add_arg(xml, "interface", "s", "in"); | |
220 | add_arg(xml, "props", "a{sv}", "out"); | |
221 | wpabuf_put_str(xml, "</method>"); | |
222 | ||
223 | wpabuf_printf(xml, "<method name=\"%s\">", WPA_DBUS_PROPERTIES_SET); | |
224 | add_arg(xml, "interface", "s", "in"); | |
225 | add_arg(xml, "propname", "s", "in"); | |
226 | add_arg(xml, "value", "v", "in"); | |
227 | wpabuf_put_str(xml, "</method>"); | |
228 | ||
229 | wpabuf_put_str(xml, "</interface>"); | |
230 | } | |
231 | ||
232 | ||
ce4f7fdb JM |
233 | static void add_wpas_interfaces(struct wpabuf *xml, |
234 | struct wpa_dbus_object_desc *obj_dsc) | |
235 | { | |
236 | struct dl_list ifaces; | |
38279bdb | 237 | |
ce4f7fdb JM |
238 | dl_list_init(&ifaces); |
239 | extract_interfaces(&ifaces, obj_dsc); | |
ce4f7fdb | 240 | add_interfaces(&ifaces, xml); |
04551ee6 JM |
241 | } |
242 | ||
243 | ||
244 | /** | |
245 | * wpa_dbus_introspect - Responds for Introspect calls on object | |
246 | * @message: Message with Introspect call | |
247 | * @obj_dsc: Object description on which Introspect was called | |
248 | * Returns: Message with introspection result XML string as only argument | |
249 | * | |
250 | * Iterates over all methods, signals and properties registered with | |
251 | * object and generates introspection data for the object as XML string. | |
252 | */ | |
253 | DBusMessage * wpa_dbus_introspect(DBusMessage *message, | |
254 | struct wpa_dbus_object_desc *obj_dsc) | |
255 | { | |
256 | ||
257 | DBusMessage *reply; | |
ce4f7fdb | 258 | struct wpabuf *xml; |
04551ee6 | 259 | |
e50c50d5 | 260 | xml = wpabuf_alloc(20000); |
ce4f7fdb JM |
261 | if (xml == NULL) |
262 | return NULL; | |
04551ee6 | 263 | |
ce4f7fdb JM |
264 | wpabuf_put_str(xml, "<?xml version=\"1.0\"?>\n"); |
265 | wpabuf_put_str(xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); | |
266 | wpabuf_put_str(xml, "<node>"); | |
04551ee6 | 267 | |
ce4f7fdb JM |
268 | add_introspectable_interface(xml); |
269 | add_properties_interface(xml); | |
270 | add_wpas_interfaces(xml, obj_dsc); | |
ce4f7fdb JM |
271 | add_child_nodes(xml, obj_dsc->connection, |
272 | dbus_message_get_path(message)); | |
d316584c | 273 | |
ce4f7fdb | 274 | wpabuf_put_str(xml, "</node>\n"); |
04551ee6 JM |
275 | |
276 | reply = dbus_message_new_method_return(message); | |
d316584c JM |
277 | if (reply) { |
278 | const char *intro_str = wpabuf_head(xml); | |
38279bdb | 279 | |
d316584c JM |
280 | dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str, |
281 | DBUS_TYPE_INVALID); | |
04551ee6 | 282 | } |
ce4f7fdb | 283 | wpabuf_free(xml); |
04551ee6 JM |
284 | |
285 | return reply; | |
286 | } |