]>
Commit | Line | Data |
---|---|---|
9abafccc JB |
1 | /* |
2 | * WPA Supplicant / dbus-based control interface (P2P) | |
d90134e7 | 3 | * Copyright (c) 2011-2012, Intel Corporation |
9abafccc | 4 | * |
d90134e7 JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
9abafccc JB |
7 | */ |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "utils/includes.h" | |
12 | #include "common.h" | |
13 | #include "../config.h" | |
14 | #include "../wpa_supplicant_i.h" | |
15 | #include "../wps_supplicant.h" | |
28550706 | 16 | #include "../notify.h" |
9abafccc JB |
17 | #include "dbus_new_helpers.h" |
18 | #include "dbus_new.h" | |
19 | #include "dbus_new_handlers.h" | |
20 | #include "dbus_new_handlers_p2p.h" | |
21 | #include "dbus_dict_helpers.h" | |
22 | #include "p2p/p2p.h" | |
23 | #include "common/ieee802_11_defs.h" | |
24 | #include "ap/hostapd.h" | |
25 | #include "ap/ap_config.h" | |
26 | #include "ap/wps_hostapd.h" | |
27 | ||
28 | #include "../p2p_supplicant.h" | |
29 | ||
30 | /** | |
31 | * Parses out the mac address from the peer object path. | |
32 | * @peer_path - object path of the form | |
33 | * /fi/w1/wpa_supplicant1/Interfaces/n/Peers/00112233445566 (no colons) | |
34 | * @addr - out param must be of ETH_ALEN size | |
35 | * Returns 0 if valid (including MAC), -1 otherwise | |
36 | */ | |
37 | static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN]) | |
38 | { | |
39 | char *p; | |
40 | ||
41 | if (!peer_path) | |
42 | return -1; | |
024d018b | 43 | p = os_strrchr(peer_path, '/'); |
9abafccc JB |
44 | if (!p) |
45 | return -1; | |
46 | p++; | |
47 | return hwaddr_compact_aton(p, addr); | |
48 | } | |
49 | ||
28550706 JS |
50 | |
51 | /** | |
52 | * wpas_dbus_error_persistent_group_unknown - Return a new PersistentGroupUnknown | |
53 | * error message | |
54 | * @message: Pointer to incoming dbus message this error refers to | |
55 | * Returns: a dbus error message | |
56 | * | |
57 | * Convenience function to create and return an invalid persistent group error. | |
58 | */ | |
59 | static DBusMessage * wpas_dbus_error_persistent_group_unknown( | |
60 | DBusMessage *message) | |
61 | { | |
62 | return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN, | |
63 | "There is no such persistent group in " | |
64 | "this P2P device."); | |
65 | } | |
66 | ||
67 | ||
f94a85ee JM |
68 | DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message, |
69 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
70 | { |
71 | struct wpa_dbus_dict_entry entry; | |
72 | DBusMessage *reply = NULL; | |
73 | DBusMessageIter iter; | |
74 | DBusMessageIter iter_dict; | |
75 | unsigned int timeout = 0; | |
9abafccc JB |
76 | enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL; |
77 | int num_req_dev_types = 0; | |
78 | unsigned int i; | |
79 | u8 *req_dev_types = NULL; | |
80 | ||
81 | dbus_message_iter_init(message, &iter); | |
e1739fb6 | 82 | entry.key = NULL; |
9abafccc | 83 | |
6aeeb6fa | 84 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
85 | goto error; |
86 | ||
87 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
88 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
89 | goto error; | |
90 | ||
91 | if (!os_strcmp(entry.key, "Timeout") && | |
92 | (entry.type == DBUS_TYPE_INT32)) { | |
93 | timeout = entry.uint32_value; | |
9abafccc JB |
94 | } else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) { |
95 | if ((entry.type != DBUS_TYPE_ARRAY) || | |
96 | (entry.array_type != WPAS_DBUS_TYPE_BINARRAY)) | |
97 | goto error_clear; | |
98 | ||
b02897e7 | 99 | os_free(req_dev_types); |
9abafccc JB |
100 | req_dev_types = |
101 | os_malloc(WPS_DEV_TYPE_LEN * entry.array_len); | |
102 | if (!req_dev_types) | |
103 | goto error_clear; | |
104 | ||
105 | for (i = 0; i < entry.array_len; i++) { | |
106 | if (wpabuf_len(entry.binarray_value[i]) != | |
107 | WPS_DEV_TYPE_LEN) | |
108 | goto error_clear; | |
109 | os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN, | |
110 | wpabuf_head(entry.binarray_value[i]), | |
111 | WPS_DEV_TYPE_LEN); | |
112 | } | |
9abafccc | 113 | num_req_dev_types = entry.array_len; |
1755b616 RC |
114 | } else if (!os_strcmp(entry.key, "DiscoveryType") && |
115 | (entry.type == DBUS_TYPE_STRING)) { | |
116 | if (!os_strcmp(entry.str_value, "start_with_full")) | |
117 | type = P2P_FIND_START_WITH_FULL; | |
118 | else if (!os_strcmp(entry.str_value, "social")) | |
119 | type = P2P_FIND_ONLY_SOCIAL; | |
120 | else if (!os_strcmp(entry.str_value, "progressive")) | |
121 | type = P2P_FIND_PROGRESSIVE; | |
122 | else | |
123 | goto error_clear; | |
9abafccc JB |
124 | } else |
125 | goto error_clear; | |
126 | wpa_dbus_dict_entry_clear(&entry); | |
127 | } | |
128 | ||
6d92fa6e | 129 | wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types, |
37448ede | 130 | NULL, 0); |
263ef84d | 131 | os_free(req_dev_types); |
9abafccc JB |
132 | return reply; |
133 | ||
134 | error_clear: | |
9abafccc JB |
135 | wpa_dbus_dict_entry_clear(&entry); |
136 | error: | |
263ef84d | 137 | os_free(req_dev_types); |
9abafccc JB |
138 | reply = wpas_dbus_error_invalid_args(message, entry.key); |
139 | return reply; | |
140 | } | |
141 | ||
f94a85ee JM |
142 | |
143 | DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message, | |
144 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
145 | { |
146 | wpas_p2p_stop_find(wpa_s); | |
147 | return NULL; | |
148 | } | |
149 | ||
f94a85ee JM |
150 | |
151 | DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message, | |
152 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
153 | { |
154 | DBusMessageIter iter; | |
155 | char *peer_object_path = NULL; | |
156 | u8 peer_addr[ETH_ALEN]; | |
157 | ||
158 | dbus_message_iter_init(message, &iter); | |
159 | dbus_message_iter_get_basic(&iter, &peer_object_path); | |
160 | ||
161 | if (parse_peer_object_path(peer_object_path, peer_addr) < 0) | |
162 | return wpas_dbus_error_invalid_args(message, NULL); | |
163 | ||
164 | if (wpas_p2p_reject(wpa_s, peer_addr) < 0) | |
165 | return wpas_dbus_error_unknown_error(message, | |
166 | "Failed to call wpas_p2p_reject method."); | |
167 | ||
168 | return NULL; | |
169 | } | |
170 | ||
f94a85ee JM |
171 | |
172 | DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message, | |
173 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
174 | { |
175 | dbus_int32_t timeout = 0; | |
176 | ||
177 | if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout, | |
178 | DBUS_TYPE_INVALID)) | |
179 | return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, | |
180 | NULL); | |
181 | ||
182 | if (wpas_p2p_listen(wpa_s, (unsigned int)timeout)) | |
183 | return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, | |
184 | NULL); | |
185 | ||
186 | return NULL; | |
187 | } | |
188 | ||
f94a85ee JM |
189 | |
190 | DBusMessage * wpas_dbus_handler_p2p_extendedlisten( | |
191 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
192 | { |
193 | unsigned int period = 0, interval = 0; | |
194 | struct wpa_dbus_dict_entry entry; | |
195 | DBusMessageIter iter; | |
196 | DBusMessageIter iter_dict; | |
197 | ||
198 | dbus_message_iter_init(message, &iter); | |
e1739fb6 | 199 | entry.key = NULL; |
9abafccc | 200 | |
6aeeb6fa | 201 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
202 | goto error; |
203 | ||
204 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
205 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
206 | goto error; | |
207 | ||
f94a85ee | 208 | if (!os_strcmp(entry.key, "period") && |
9abafccc JB |
209 | (entry.type == DBUS_TYPE_INT32)) |
210 | period = entry.uint32_value; | |
f94a85ee | 211 | else if (!os_strcmp(entry.key, "interval") && |
9abafccc JB |
212 | (entry.type == DBUS_TYPE_INT32)) |
213 | interval = entry.uint32_value; | |
214 | else | |
215 | goto error_clear; | |
216 | wpa_dbus_dict_entry_clear(&entry); | |
217 | } | |
218 | ||
219 | if (wpas_p2p_ext_listen(wpa_s, period, interval)) | |
f94a85ee JM |
220 | return wpas_dbus_error_unknown_error( |
221 | message, "failed to initiate a p2p_ext_listen."); | |
9abafccc JB |
222 | |
223 | return NULL; | |
224 | ||
225 | error_clear: | |
226 | wpa_dbus_dict_entry_clear(&entry); | |
227 | error: | |
228 | return wpas_dbus_error_invalid_args(message, entry.key); | |
229 | } | |
230 | ||
f94a85ee JM |
231 | |
232 | DBusMessage * wpas_dbus_handler_p2p_presence_request( | |
233 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
234 | { |
235 | unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0; | |
236 | struct wpa_dbus_dict_entry entry; | |
237 | DBusMessageIter iter; | |
238 | DBusMessageIter iter_dict; | |
239 | ||
240 | dbus_message_iter_init(message, &iter); | |
e1739fb6 | 241 | entry.key = NULL; |
9abafccc | 242 | |
6aeeb6fa | 243 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
244 | goto error; |
245 | ||
246 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
247 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
248 | goto error; | |
249 | ||
f94a85ee | 250 | if (!os_strcmp(entry.key, "duration1") && |
9abafccc JB |
251 | (entry.type == DBUS_TYPE_INT32)) |
252 | dur1 = entry.uint32_value; | |
f94a85ee | 253 | else if (!os_strcmp(entry.key, "interval1") && |
9abafccc JB |
254 | entry.type == DBUS_TYPE_INT32) |
255 | int1 = entry.uint32_value; | |
f94a85ee | 256 | else if (!os_strcmp(entry.key, "duration2") && |
9abafccc JB |
257 | entry.type == DBUS_TYPE_INT32) |
258 | dur2 = entry.uint32_value; | |
f94a85ee | 259 | else if (!os_strcmp(entry.key, "interval2") && |
9abafccc JB |
260 | entry.type == DBUS_TYPE_INT32) |
261 | int2 = entry.uint32_value; | |
262 | else | |
263 | goto error_clear; | |
264 | ||
265 | wpa_dbus_dict_entry_clear(&entry); | |
266 | } | |
267 | if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0) | |
268 | return wpas_dbus_error_unknown_error(message, | |
269 | "Failed to invoke presence request."); | |
270 | ||
271 | return NULL; | |
272 | ||
273 | error_clear: | |
274 | wpa_dbus_dict_entry_clear(&entry); | |
275 | error: | |
276 | return wpas_dbus_error_invalid_args(message, entry.key); | |
277 | } | |
278 | ||
f94a85ee JM |
279 | |
280 | DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, | |
281 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
282 | { |
283 | DBusMessageIter iter_dict; | |
284 | DBusMessage *reply = NULL; | |
285 | DBusMessageIter iter; | |
286 | struct wpa_dbus_dict_entry entry; | |
28550706 | 287 | char *pg_object_path = NULL; |
9abafccc JB |
288 | int persistent_group = 0; |
289 | int freq = 0; | |
290 | char *iface = NULL; | |
291 | char *net_id_str = NULL; | |
292 | unsigned int group_id = 0; | |
293 | struct wpa_ssid *ssid; | |
294 | ||
295 | dbus_message_iter_init(message, &iter); | |
296 | ||
6aeeb6fa | 297 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
298 | goto inv_args; |
299 | ||
300 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
301 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
302 | goto inv_args; | |
303 | ||
f94a85ee | 304 | if (!os_strcmp(entry.key, "persistent") && |
9abafccc JB |
305 | (entry.type == DBUS_TYPE_BOOLEAN)) { |
306 | persistent_group = (entry.bool_value == TRUE) ? 1 : 0; | |
f94a85ee | 307 | } else if (!os_strcmp(entry.key, "frequency") && |
9abafccc JB |
308 | (entry.type == DBUS_TYPE_INT32)) { |
309 | freq = entry.int32_value; | |
310 | if (freq <= 0) | |
311 | goto inv_args_clear; | |
f94a85ee | 312 | } else if (!os_strcmp(entry.key, "persistent_group_object") && |
9abafccc | 313 | entry.type == DBUS_TYPE_OBJECT_PATH) |
28550706 | 314 | pg_object_path = os_strdup(entry.str_value); |
9abafccc JB |
315 | else |
316 | goto inv_args_clear; | |
317 | ||
318 | wpa_dbus_dict_entry_clear(&entry); | |
319 | } | |
320 | ||
28550706 | 321 | if (pg_object_path != NULL) { |
9abafccc | 322 | /* |
28550706 JS |
323 | * A persistent group Object Path is defined meaning we want |
324 | * to re-invoke a persistent group. | |
9abafccc JB |
325 | */ |
326 | ||
28550706 | 327 | iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, |
9abafccc JB |
328 | &net_id_str, NULL); |
329 | if (iface == NULL || | |
330 | os_strcmp(iface, wpa_s->dbus_new_path) != 0) { | |
331 | reply = | |
332 | wpas_dbus_error_invalid_args(message, | |
28550706 | 333 | pg_object_path); |
9abafccc JB |
334 | goto out; |
335 | } | |
336 | ||
337 | group_id = strtoul(net_id_str, NULL, 10); | |
338 | if (errno == EINVAL) { | |
339 | reply = wpas_dbus_error_invalid_args( | |
28550706 | 340 | message, pg_object_path); |
9abafccc JB |
341 | goto out; |
342 | } | |
343 | ||
ffbf1eaa | 344 | /* Get the SSID structure from the persistent group id */ |
9abafccc JB |
345 | ssid = wpa_config_get_network(wpa_s->conf, group_id); |
346 | if (ssid == NULL || ssid->disabled != 2) | |
347 | goto inv_args; | |
348 | ||
7aeac985 | 349 | if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0)) { |
f94a85ee JM |
350 | reply = wpas_dbus_error_unknown_error( |
351 | message, | |
352 | "Failed to reinvoke a persistent group"); | |
9abafccc JB |
353 | goto out; |
354 | } | |
7aeac985 | 355 | } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0)) |
9abafccc JB |
356 | goto inv_args; |
357 | ||
358 | out: | |
28550706 | 359 | os_free(pg_object_path); |
9abafccc JB |
360 | os_free(net_id_str); |
361 | os_free(iface); | |
362 | return reply; | |
363 | inv_args_clear: | |
364 | wpa_dbus_dict_entry_clear(&entry); | |
365 | inv_args: | |
366 | reply = wpas_dbus_error_invalid_args(message, NULL); | |
367 | goto out; | |
368 | } | |
369 | ||
f94a85ee JM |
370 | |
371 | DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message, | |
372 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
373 | { |
374 | if (wpas_p2p_disconnect(wpa_s)) | |
375 | return wpas_dbus_error_unknown_error(message, | |
376 | "failed to disconnect"); | |
377 | ||
378 | return NULL; | |
379 | } | |
380 | ||
f94a85ee | 381 | |
e9ae4059 DW |
382 | static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s, |
383 | DBusMessage *message, | |
384 | DBusMessage **out_reply, | |
385 | DBusError *error) | |
386 | { | |
387 | /* Return an error message or an error if P2P isn't available */ | |
388 | if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) { | |
389 | if (out_reply) { | |
390 | *out_reply = dbus_message_new_error( | |
391 | message, DBUS_ERROR_FAILED, | |
392 | "P2P is not available for this interface"); | |
393 | } | |
394 | dbus_set_error_const(error, DBUS_ERROR_FAILED, | |
395 | "P2P is not available for this " | |
396 | "interface"); | |
397 | return FALSE; | |
398 | } | |
399 | return TRUE; | |
400 | } | |
401 | ||
402 | ||
f94a85ee JM |
403 | DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message, |
404 | struct wpa_supplicant *wpa_s) | |
9abafccc | 405 | { |
e9ae4059 DW |
406 | DBusMessage *reply = NULL; |
407 | ||
408 | if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) | |
409 | return reply; | |
410 | ||
9abafccc JB |
411 | os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN); |
412 | wpa_s->force_long_sd = 0; | |
413 | p2p_flush(wpa_s->global->p2p); | |
414 | ||
415 | return NULL; | |
416 | } | |
417 | ||
f94a85ee JM |
418 | |
419 | DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message, | |
420 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
421 | { |
422 | DBusMessageIter iter_dict; | |
423 | DBusMessage *reply = NULL; | |
424 | DBusMessageIter iter; | |
425 | struct wpa_dbus_dict_entry entry; | |
426 | char *peer_object_path = NULL; | |
427 | int persistent_group = 0; | |
428 | int join = 0; | |
429 | int authorize_only = 0; | |
430 | int go_intent = -1; | |
431 | int freq = 0; | |
432 | u8 addr[ETH_ALEN]; | |
433 | char *pin = NULL; | |
434 | enum p2p_wps_method wps_method = WPS_NOT_READY; | |
435 | int new_pin; | |
436 | char *err_msg = NULL; | |
437 | char *iface = NULL; | |
438 | ||
e9ae4059 DW |
439 | if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) |
440 | return reply; | |
441 | ||
9abafccc JB |
442 | dbus_message_iter_init(message, &iter); |
443 | ||
6aeeb6fa | 444 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
445 | goto inv_args; |
446 | ||
447 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
448 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
449 | goto inv_args; | |
450 | ||
f94a85ee | 451 | if (!os_strcmp(entry.key, "peer") && |
9abafccc JB |
452 | (entry.type == DBUS_TYPE_OBJECT_PATH)) { |
453 | peer_object_path = os_strdup(entry.str_value); | |
f94a85ee | 454 | } else if (!os_strcmp(entry.key, "persistent") && |
9abafccc JB |
455 | (entry.type == DBUS_TYPE_BOOLEAN)) { |
456 | persistent_group = (entry.bool_value == TRUE) ? 1 : 0; | |
f94a85ee | 457 | } else if (!os_strcmp(entry.key, "join") && |
9abafccc JB |
458 | (entry.type == DBUS_TYPE_BOOLEAN)) { |
459 | join = (entry.bool_value == TRUE) ? 1 : 0; | |
f94a85ee | 460 | } else if (!os_strcmp(entry.key, "authorize_only") && |
9abafccc JB |
461 | (entry.type == DBUS_TYPE_BOOLEAN)) { |
462 | authorize_only = (entry.bool_value == TRUE) ? 1 : 0; | |
f94a85ee | 463 | } else if (!os_strcmp(entry.key, "frequency") && |
9abafccc JB |
464 | (entry.type == DBUS_TYPE_INT32)) { |
465 | freq = entry.int32_value; | |
466 | if (freq <= 0) | |
467 | goto inv_args_clear; | |
f94a85ee | 468 | } else if (!os_strcmp(entry.key, "go_intent") && |
9abafccc JB |
469 | (entry.type == DBUS_TYPE_INT32)) { |
470 | go_intent = entry.int32_value; | |
471 | if ((go_intent < 0) || (go_intent > 15)) | |
472 | goto inv_args_clear; | |
f94a85ee | 473 | } else if (!os_strcmp(entry.key, "wps_method") && |
9abafccc | 474 | (entry.type == DBUS_TYPE_STRING)) { |
f94a85ee | 475 | if (!os_strcmp(entry.str_value, "pbc")) |
9abafccc | 476 | wps_method = WPS_PBC; |
f94a85ee | 477 | else if (!os_strcmp(entry.str_value, "pin")) |
9abafccc | 478 | wps_method = WPS_PIN_DISPLAY; |
f94a85ee | 479 | else if (!os_strcmp(entry.str_value, "display")) |
9abafccc | 480 | wps_method = WPS_PIN_DISPLAY; |
f94a85ee | 481 | else if (!os_strcmp(entry.str_value, "keypad")) |
9abafccc JB |
482 | wps_method = WPS_PIN_KEYPAD; |
483 | else | |
484 | goto inv_args_clear; | |
f94a85ee | 485 | } else if (!os_strcmp(entry.key, "pin") && |
9abafccc JB |
486 | (entry.type == DBUS_TYPE_STRING)) { |
487 | pin = os_strdup(entry.str_value); | |
488 | } else | |
489 | goto inv_args_clear; | |
490 | ||
491 | wpa_dbus_dict_entry_clear(&entry); | |
492 | } | |
493 | ||
494 | if (!peer_object_path || (wps_method == WPS_NOT_READY) || | |
495 | (parse_peer_object_path(peer_object_path, addr) < 0) || | |
b3bcc0f5 | 496 | !p2p_peer_known(wpa_s->global->p2p, addr)) |
9abafccc | 497 | goto inv_args; |
9abafccc JB |
498 | |
499 | /* | |
500 | * Validate the wps_method specified and the pin value. | |
501 | */ | |
07fecd39 | 502 | if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD)) |
9abafccc JB |
503 | goto inv_args; |
504 | ||
505 | new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method, | |
b31be3a0 | 506 | persistent_group, 0, join, authorize_only, |
e2308e4b | 507 | go_intent, freq, -1, 0, 0); |
9abafccc JB |
508 | |
509 | if (new_pin >= 0) { | |
97a8cbb8 RC |
510 | char npin[9]; |
511 | char *generated_pin; | |
512 | os_snprintf(npin, sizeof(npin), "%08d", new_pin); | |
513 | generated_pin = npin; | |
9abafccc | 514 | reply = dbus_message_new_method_return(message); |
97a8cbb8 RC |
515 | dbus_message_append_args(reply, DBUS_TYPE_STRING, |
516 | &generated_pin, DBUS_TYPE_INVALID); | |
9abafccc JB |
517 | } else { |
518 | switch (new_pin) { | |
519 | case -2: | |
e24b9182 JM |
520 | err_msg = "connect failed due to channel " |
521 | "unavailability."; | |
9abafccc JB |
522 | iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE; |
523 | break; | |
524 | ||
525 | case -3: | |
e24b9182 | 526 | err_msg = "connect failed due to unsupported channel."; |
9abafccc JB |
527 | iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED; |
528 | break; | |
529 | ||
530 | default: | |
e24b9182 | 531 | err_msg = "connect failed due to unspecified error."; |
9abafccc JB |
532 | iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR; |
533 | break; | |
534 | } | |
e24b9182 | 535 | |
9abafccc | 536 | /* |
e24b9182 | 537 | * TODO: |
9abafccc JB |
538 | * Do we need specialized errors corresponding to above |
539 | * error conditions as against just returning a different | |
540 | * error message? | |
541 | */ | |
542 | reply = dbus_message_new_error(message, iface, err_msg); | |
543 | } | |
544 | ||
545 | out: | |
546 | os_free(peer_object_path); | |
547 | os_free(pin); | |
548 | return reply; | |
549 | inv_args_clear: | |
550 | wpa_dbus_dict_entry_clear(&entry); | |
551 | inv_args: | |
552 | reply = wpas_dbus_error_invalid_args(message, NULL); | |
553 | goto out; | |
554 | } | |
555 | ||
f94a85ee JM |
556 | |
557 | DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message, | |
558 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
559 | { |
560 | DBusMessageIter iter_dict; | |
561 | DBusMessage *reply = NULL; | |
562 | DBusMessageIter iter; | |
563 | struct wpa_dbus_dict_entry entry; | |
564 | char *peer_object_path = NULL; | |
28550706 | 565 | char *pg_object_path = NULL; |
9abafccc JB |
566 | char *iface = NULL; |
567 | char *net_id_str = NULL; | |
568 | u8 peer_addr[ETH_ALEN]; | |
569 | unsigned int group_id = 0; | |
570 | int persistent = 0; | |
571 | struct wpa_ssid *ssid; | |
572 | ||
e9ae4059 DW |
573 | if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL)) |
574 | return reply; | |
575 | ||
9abafccc JB |
576 | dbus_message_iter_init(message, &iter); |
577 | ||
6aeeb6fa | 578 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
579 | goto err; |
580 | ||
581 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
582 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
583 | goto err; | |
584 | ||
f94a85ee | 585 | if (!os_strcmp(entry.key, "peer") && |
9abafccc JB |
586 | (entry.type == DBUS_TYPE_OBJECT_PATH)) { |
587 | peer_object_path = os_strdup(entry.str_value); | |
588 | wpa_dbus_dict_entry_clear(&entry); | |
f94a85ee | 589 | } else if (!os_strcmp(entry.key, "persistent_group_object") && |
9abafccc | 590 | (entry.type == DBUS_TYPE_OBJECT_PATH)) { |
28550706 | 591 | pg_object_path = os_strdup(entry.str_value); |
9abafccc JB |
592 | persistent = 1; |
593 | wpa_dbus_dict_entry_clear(&entry); | |
594 | } else { | |
595 | wpa_dbus_dict_entry_clear(&entry); | |
596 | goto err; | |
597 | } | |
598 | } | |
599 | ||
600 | if (!peer_object_path || | |
601 | (parse_peer_object_path(peer_object_path, peer_addr) < 0) || | |
b3bcc0f5 | 602 | !p2p_peer_known(wpa_s->global->p2p, peer_addr)) { |
9abafccc JB |
603 | goto err; |
604 | } | |
605 | ||
606 | if (persistent) { | |
607 | /* | |
608 | * A group ID is defined meaning we want to re-invoke a | |
ffbf1eaa | 609 | * persistent group |
9abafccc JB |
610 | */ |
611 | ||
28550706 | 612 | iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1, |
9abafccc JB |
613 | &net_id_str, NULL); |
614 | if (iface == NULL || | |
615 | os_strcmp(iface, wpa_s->dbus_new_path) != 0) { | |
f94a85ee JM |
616 | reply = wpas_dbus_error_invalid_args(message, |
617 | pg_object_path); | |
9abafccc JB |
618 | goto out; |
619 | } | |
620 | ||
621 | group_id = strtoul(net_id_str, NULL, 10); | |
622 | if (errno == EINVAL) { | |
623 | reply = wpas_dbus_error_invalid_args( | |
f94a85ee | 624 | message, pg_object_path); |
9abafccc JB |
625 | goto out; |
626 | } | |
627 | ||
ffbf1eaa | 628 | /* Get the SSID structure from the persistent group id */ |
9abafccc JB |
629 | ssid = wpa_config_get_network(wpa_s->conf, group_id); |
630 | if (ssid == NULL || ssid->disabled != 2) | |
631 | goto err; | |
632 | ||
4d32c0c4 | 633 | if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0) < 0) { |
9abafccc | 634 | reply = wpas_dbus_error_unknown_error( |
f94a85ee JM |
635 | message, |
636 | "Failed to reinvoke a persistent group"); | |
9abafccc JB |
637 | goto out; |
638 | } | |
639 | } else { | |
640 | /* | |
641 | * No group ID means propose to a peer to join my active group | |
642 | */ | |
643 | if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname, | |
f94a85ee | 644 | peer_addr, NULL)) { |
9abafccc | 645 | reply = wpas_dbus_error_unknown_error( |
f94a85ee | 646 | message, "Failed to join to an active group"); |
9abafccc JB |
647 | goto out; |
648 | } | |
649 | } | |
650 | ||
651 | out: | |
28550706 | 652 | os_free(pg_object_path); |
9abafccc JB |
653 | os_free(peer_object_path); |
654 | return reply; | |
655 | ||
656 | err: | |
657 | reply = wpas_dbus_error_invalid_args(message, NULL); | |
658 | goto out; | |
659 | } | |
660 | ||
f94a85ee JM |
661 | |
662 | DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message, | |
663 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
664 | { |
665 | DBusMessageIter iter; | |
666 | char *peer_object_path = NULL; | |
667 | char *config_method = NULL; | |
668 | u8 peer_addr[ETH_ALEN]; | |
669 | ||
670 | dbus_message_iter_init(message, &iter); | |
671 | dbus_message_iter_get_basic(&iter, &peer_object_path); | |
672 | ||
673 | if (parse_peer_object_path(peer_object_path, peer_addr) < 0) | |
674 | return wpas_dbus_error_invalid_args(message, NULL); | |
675 | ||
676 | dbus_message_iter_next(&iter); | |
677 | dbus_message_iter_get_basic(&iter, &config_method); | |
678 | ||
679 | /* | |
680 | * Validation checks on config_method are being duplicated here | |
681 | * to be able to return invalid args reply since the error code | |
682 | * from p2p module are not granular enough (yet). | |
683 | */ | |
684 | if (os_strcmp(config_method, "display") && | |
685 | os_strcmp(config_method, "keypad") && | |
686 | os_strcmp(config_method, "pbc") && | |
687 | os_strcmp(config_method, "pushbutton")) | |
688 | return wpas_dbus_error_invalid_args(message, NULL); | |
689 | ||
0918c4bf JM |
690 | if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, |
691 | WPAS_P2P_PD_FOR_GO_NEG) < 0) | |
9abafccc JB |
692 | return wpas_dbus_error_unknown_error(message, |
693 | "Failed to send provision discovery request"); | |
694 | ||
695 | return NULL; | |
696 | } | |
697 | ||
f94a85ee | 698 | |
9abafccc JB |
699 | /* |
700 | * P2P Device property accessor methods. | |
701 | */ | |
702 | ||
cca0060f NS |
703 | dbus_bool_t wpas_dbus_getter_p2p_device_config(DBusMessageIter *iter, |
704 | DBusError *error, | |
705 | void *user_data) | |
9abafccc | 706 | { |
6aeeb6fa DW |
707 | struct wpa_supplicant *wpa_s = user_data; |
708 | DBusMessageIter variant_iter, dict_iter; | |
a362dc1d JS |
709 | DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val, |
710 | iter_secdev_dict_array; | |
9abafccc | 711 | const char *dev_name; |
9abafccc JB |
712 | int num_vendor_extensions = 0; |
713 | int i; | |
714 | const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT]; | |
715 | ||
e9ae4059 DW |
716 | if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) |
717 | return FALSE; | |
718 | ||
6aeeb6fa | 719 | if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, |
9abafccc JB |
720 | "a{sv}", &variant_iter) || |
721 | !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) | |
722 | goto err_no_mem; | |
723 | ||
724 | /* DeviceName */ | |
725 | dev_name = wpa_s->conf->device_name; | |
726 | if (dev_name && | |
727 | !wpa_dbus_dict_append_string(&dict_iter, "DeviceName", dev_name)) | |
728 | goto err_no_mem; | |
729 | ||
730 | /* Primary device type */ | |
731 | if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType", | |
732 | (char *)wpa_s->conf->device_type, | |
733 | WPS_DEV_TYPE_LEN)) | |
734 | goto err_no_mem; | |
735 | ||
736 | /* Secondary device types */ | |
a362dc1d JS |
737 | if (wpa_s->conf->num_sec_device_types) { |
738 | if (!wpa_dbus_dict_begin_array(&dict_iter, | |
739 | "SecondaryDeviceTypes", | |
740 | DBUS_TYPE_ARRAY_AS_STRING | |
741 | DBUS_TYPE_BYTE_AS_STRING, | |
742 | &iter_secdev_dict_entry, | |
743 | &iter_secdev_dict_val, | |
744 | &iter_secdev_dict_array)) | |
745 | goto err_no_mem; | |
746 | ||
747 | for (i = 0; i < wpa_s->conf->num_sec_device_types; i++) | |
748 | wpa_dbus_dict_bin_array_add_element( | |
749 | &iter_secdev_dict_array, | |
750 | wpa_s->conf->sec_device_type[i], | |
751 | WPS_DEV_TYPE_LEN); | |
752 | ||
753 | if (!wpa_dbus_dict_end_array(&dict_iter, | |
754 | &iter_secdev_dict_entry, | |
755 | &iter_secdev_dict_val, | |
756 | &iter_secdev_dict_array)) | |
757 | goto err_no_mem; | |
9abafccc JB |
758 | } |
759 | ||
9abafccc JB |
760 | /* Vendor Extensions */ |
761 | for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { | |
762 | if (wpa_s->conf->wps_vendor_ext[i] == NULL) | |
763 | continue; | |
764 | vendor_ext[num_vendor_extensions++] = | |
765 | wpa_s->conf->wps_vendor_ext[i]; | |
766 | } | |
767 | ||
768 | if (num_vendor_extensions && | |
769 | !wpa_dbus_dict_append_wpabuf_array(&dict_iter, | |
770 | "VendorExtension", | |
771 | vendor_ext, | |
772 | num_vendor_extensions)) | |
773 | goto err_no_mem; | |
774 | ||
775 | /* GO Intent */ | |
776 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent", | |
777 | wpa_s->conf->p2p_go_intent)) | |
778 | goto err_no_mem; | |
779 | ||
ffbf1eaa | 780 | /* Persistent Reconnect */ |
cca0060f | 781 | if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect", |
9abafccc JB |
782 | wpa_s->conf->persistent_reconnect)) |
783 | goto err_no_mem; | |
784 | ||
785 | /* Listen Reg Class */ | |
786 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass", | |
787 | wpa_s->conf->p2p_listen_reg_class)) | |
788 | goto err_no_mem; | |
789 | ||
790 | /* Listen Channel */ | |
791 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel", | |
792 | wpa_s->conf->p2p_listen_channel)) | |
793 | goto err_no_mem; | |
794 | ||
795 | /* Oper Reg Class */ | |
796 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass", | |
797 | wpa_s->conf->p2p_oper_reg_class)) | |
798 | goto err_no_mem; | |
799 | ||
800 | /* Oper Channel */ | |
801 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel", | |
802 | wpa_s->conf->p2p_oper_channel)) | |
803 | goto err_no_mem; | |
804 | ||
805 | /* SSID Postfix */ | |
806 | if (wpa_s->conf->p2p_ssid_postfix && | |
807 | !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix", | |
808 | wpa_s->conf->p2p_ssid_postfix)) | |
809 | goto err_no_mem; | |
810 | ||
811 | /* Intra Bss */ | |
812 | if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss", | |
813 | wpa_s->conf->p2p_intra_bss)) | |
814 | goto err_no_mem; | |
815 | ||
816 | /* Group Idle */ | |
817 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle", | |
818 | wpa_s->conf->p2p_group_idle)) | |
819 | goto err_no_mem; | |
820 | ||
5d5fe8ed JS |
821 | /* Dissasociation low ack */ |
822 | if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack", | |
823 | wpa_s->conf->disassoc_low_ack)) | |
824 | goto err_no_mem; | |
825 | ||
9abafccc | 826 | if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) || |
6aeeb6fa | 827 | !dbus_message_iter_close_container(iter, &variant_iter)) |
9abafccc JB |
828 | goto err_no_mem; |
829 | ||
6aeeb6fa DW |
830 | return TRUE; |
831 | ||
9abafccc | 832 | err_no_mem: |
6aeeb6fa DW |
833 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); |
834 | return FALSE; | |
9abafccc JB |
835 | } |
836 | ||
f94a85ee | 837 | |
cca0060f NS |
838 | dbus_bool_t wpas_dbus_setter_p2p_device_config(DBusMessageIter *iter, |
839 | DBusError *error, | |
840 | void *user_data) | |
9abafccc | 841 | { |
6aeeb6fa DW |
842 | struct wpa_supplicant *wpa_s = user_data; |
843 | DBusMessageIter variant_iter, iter_dict; | |
9abafccc | 844 | struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING }; |
9abafccc JB |
845 | unsigned int i; |
846 | ||
e9ae4059 DW |
847 | if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) |
848 | return FALSE; | |
849 | ||
6aeeb6fa DW |
850 | dbus_message_iter_recurse(iter, &variant_iter); |
851 | if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error)) | |
852 | return FALSE; | |
9abafccc JB |
853 | |
854 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
6aeeb6fa DW |
855 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { |
856 | dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, | |
857 | "invalid message format"); | |
858 | return FALSE; | |
859 | } | |
9abafccc JB |
860 | |
861 | if (os_strcmp(entry.key, "DeviceName") == 0) { | |
862 | char *devname; | |
863 | ||
864 | if (entry.type != DBUS_TYPE_STRING) | |
6aeeb6fa | 865 | goto error; |
9abafccc JB |
866 | |
867 | devname = os_strdup(entry.str_value); | |
868 | if (devname == NULL) | |
869 | goto err_no_mem_clear; | |
870 | ||
871 | os_free(wpa_s->conf->device_name); | |
872 | wpa_s->conf->device_name = devname; | |
873 | ||
874 | wpa_s->conf->changed_parameters |= | |
f94a85ee | 875 | CFG_CHANGED_DEVICE_NAME; |
9abafccc JB |
876 | } else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) { |
877 | if (entry.type != DBUS_TYPE_ARRAY || | |
878 | entry.array_type != DBUS_TYPE_BYTE || | |
879 | entry.array_len != WPS_DEV_TYPE_LEN) | |
6aeeb6fa | 880 | goto error; |
9abafccc JB |
881 | |
882 | os_memcpy(wpa_s->conf->device_type, | |
883 | entry.bytearray_value, | |
884 | WPS_DEV_TYPE_LEN); | |
885 | wpa_s->conf->changed_parameters |= | |
886 | CFG_CHANGED_DEVICE_TYPE; | |
887 | } else if (os_strcmp(entry.key, "SecondaryDeviceTypes") == 0) { | |
888 | if (entry.type != DBUS_TYPE_ARRAY || | |
889 | entry.array_type != WPAS_DBUS_TYPE_BINARRAY || | |
890 | entry.array_len > MAX_SEC_DEVICE_TYPES) | |
891 | goto error; | |
892 | ||
893 | for (i = 0; i < entry.array_len; i++) | |
f94a85ee JM |
894 | if (wpabuf_len(entry.binarray_value[i]) != |
895 | WPS_DEV_TYPE_LEN) | |
9abafccc JB |
896 | goto err_no_mem_clear; |
897 | for (i = 0; i < entry.array_len; i++) | |
898 | os_memcpy(wpa_s->conf->sec_device_type[i], | |
899 | wpabuf_head(entry.binarray_value[i]), | |
900 | WPS_DEV_TYPE_LEN); | |
901 | wpa_s->conf->num_sec_device_types = entry.array_len; | |
902 | wpa_s->conf->changed_parameters |= | |
903 | CFG_CHANGED_SEC_DEVICE_TYPE; | |
904 | } else if (os_strcmp(entry.key, "VendorExtension") == 0) { | |
905 | if ((entry.type != DBUS_TYPE_ARRAY) || | |
906 | (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) || | |
907 | (entry.array_len > P2P_MAX_WPS_VENDOR_EXT)) | |
6aeeb6fa | 908 | goto error; |
9abafccc JB |
909 | |
910 | wpa_s->conf->changed_parameters |= | |
f94a85ee | 911 | CFG_CHANGED_VENDOR_EXTENSION; |
9abafccc JB |
912 | |
913 | for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { | |
914 | wpabuf_free(wpa_s->conf->wps_vendor_ext[i]); | |
915 | if (i < entry.array_len) { | |
916 | wpa_s->conf->wps_vendor_ext[i] = | |
917 | entry.binarray_value[i]; | |
918 | entry.binarray_value[i] = NULL; | |
919 | } else | |
920 | wpa_s->conf->wps_vendor_ext[i] = NULL; | |
921 | } | |
922 | } else if ((os_strcmp(entry.key, "GOIntent") == 0) && | |
923 | (entry.type == DBUS_TYPE_UINT32) && | |
924 | (entry.uint32_value <= 15)) | |
925 | wpa_s->conf->p2p_go_intent = entry.uint32_value; | |
cca0060f | 926 | else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) && |
9abafccc JB |
927 | (entry.type == DBUS_TYPE_BOOLEAN)) |
928 | wpa_s->conf->persistent_reconnect = entry.bool_value; | |
9abafccc | 929 | else if ((os_strcmp(entry.key, "ListenRegClass") == 0) && |
2463ba70 | 930 | (entry.type == DBUS_TYPE_UINT32)) { |
9abafccc | 931 | wpa_s->conf->p2p_listen_reg_class = entry.uint32_value; |
2463ba70 JS |
932 | wpa_s->conf->changed_parameters |= |
933 | CFG_CHANGED_P2P_LISTEN_CHANNEL; | |
934 | } else if ((os_strcmp(entry.key, "ListenChannel") == 0) && | |
935 | (entry.type == DBUS_TYPE_UINT32)) { | |
9abafccc | 936 | wpa_s->conf->p2p_listen_channel = entry.uint32_value; |
2463ba70 JS |
937 | wpa_s->conf->changed_parameters |= |
938 | CFG_CHANGED_P2P_LISTEN_CHANNEL; | |
939 | } else if ((os_strcmp(entry.key, "OperRegClass") == 0) && | |
940 | (entry.type == DBUS_TYPE_UINT32)) { | |
9abafccc | 941 | wpa_s->conf->p2p_oper_reg_class = entry.uint32_value; |
2463ba70 JS |
942 | wpa_s->conf->changed_parameters |= |
943 | CFG_CHANGED_P2P_OPER_CHANNEL; | |
944 | } else if ((os_strcmp(entry.key, "OperChannel") == 0) && | |
945 | (entry.type == DBUS_TYPE_UINT32)) { | |
9abafccc | 946 | wpa_s->conf->p2p_oper_channel = entry.uint32_value; |
2463ba70 JS |
947 | wpa_s->conf->changed_parameters |= |
948 | CFG_CHANGED_P2P_OPER_CHANNEL; | |
949 | } else if (os_strcmp(entry.key, "SsidPostfix") == 0) { | |
9abafccc JB |
950 | char *postfix; |
951 | ||
952 | if (entry.type != DBUS_TYPE_STRING) | |
6aeeb6fa | 953 | goto error; |
9abafccc JB |
954 | |
955 | postfix = os_strdup(entry.str_value); | |
956 | if (!postfix) | |
957 | goto err_no_mem_clear; | |
958 | ||
959 | os_free(wpa_s->conf->p2p_ssid_postfix); | |
960 | wpa_s->conf->p2p_ssid_postfix = postfix; | |
961 | ||
962 | wpa_s->conf->changed_parameters |= | |
963 | CFG_CHANGED_P2P_SSID_POSTFIX; | |
964 | } else if ((os_strcmp(entry.key, "IntraBss") == 0) && | |
965 | (entry.type == DBUS_TYPE_BOOLEAN)) { | |
966 | wpa_s->conf->p2p_intra_bss = entry.bool_value; | |
967 | wpa_s->conf->changed_parameters |= | |
f94a85ee | 968 | CFG_CHANGED_P2P_INTRA_BSS; |
9abafccc JB |
969 | } else if ((os_strcmp(entry.key, "GroupIdle") == 0) && |
970 | (entry.type == DBUS_TYPE_UINT32)) | |
971 | wpa_s->conf->p2p_group_idle = entry.uint32_value; | |
5d5fe8ed JS |
972 | else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 && |
973 | entry.type == DBUS_TYPE_UINT32) | |
974 | wpa_s->conf->disassoc_low_ack = entry.uint32_value; | |
9abafccc | 975 | else |
6aeeb6fa | 976 | goto error; |
9abafccc JB |
977 | |
978 | wpa_dbus_dict_entry_clear(&entry); | |
979 | } | |
980 | ||
981 | if (wpa_s->conf->changed_parameters) { | |
982 | /* Some changed parameters requires to update config*/ | |
983 | wpa_supplicant_update_config(wpa_s); | |
984 | } | |
985 | ||
6aeeb6fa | 986 | return TRUE; |
9abafccc | 987 | |
9abafccc | 988 | error: |
6aeeb6fa DW |
989 | dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, |
990 | "invalid message format"); | |
9abafccc | 991 | wpa_dbus_dict_entry_clear(&entry); |
6aeeb6fa | 992 | return FALSE; |
9abafccc | 993 | |
9abafccc | 994 | err_no_mem_clear: |
6aeeb6fa | 995 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); |
9abafccc | 996 | wpa_dbus_dict_entry_clear(&entry); |
6aeeb6fa | 997 | return FALSE; |
9abafccc JB |
998 | } |
999 | ||
f94a85ee | 1000 | |
6aeeb6fa DW |
1001 | dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error, |
1002 | void *user_data) | |
9abafccc | 1003 | { |
6aeeb6fa | 1004 | struct wpa_supplicant *wpa_s = user_data; |
9abafccc JB |
1005 | struct p2p_data *p2p = wpa_s->global->p2p; |
1006 | int next = 0, i = 0; | |
1007 | int num = 0, out_of_mem = 0; | |
1008 | const u8 *addr; | |
1009 | const struct p2p_peer_info *peer_info = NULL; | |
6aeeb6fa | 1010 | dbus_bool_t success = FALSE; |
9abafccc JB |
1011 | |
1012 | struct dl_list peer_objpath_list; | |
1013 | struct peer_objpath_node { | |
1014 | struct dl_list list; | |
1015 | char path[WPAS_DBUS_OBJECT_PATH_MAX]; | |
1016 | } *node, *tmp; | |
1017 | ||
1018 | char **peer_obj_paths = NULL; | |
1019 | ||
e9ae4059 DW |
1020 | if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error)) |
1021 | return FALSE; | |
1022 | ||
9abafccc JB |
1023 | dl_list_init(&peer_objpath_list); |
1024 | ||
1025 | /* Get the first peer info */ | |
1026 | peer_info = p2p_get_peer_found(p2p, NULL, next); | |
1027 | ||
1028 | /* Get next and accumulate them */ | |
1029 | next = 1; | |
1030 | while (peer_info != NULL) { | |
1031 | node = os_zalloc(sizeof(struct peer_objpath_node)); | |
1032 | if (!node) { | |
1033 | out_of_mem = 1; | |
1034 | goto error; | |
1035 | } | |
1036 | ||
1037 | addr = peer_info->p2p_device_addr; | |
1038 | os_snprintf(node->path, WPAS_DBUS_OBJECT_PATH_MAX, | |
1039 | "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART | |
1040 | "/" COMPACT_MACSTR, | |
1041 | wpa_s->dbus_new_path, MAC2STR(addr)); | |
1042 | dl_list_add_tail(&peer_objpath_list, &node->list); | |
1043 | num++; | |
1044 | ||
1045 | peer_info = p2p_get_peer_found(p2p, addr, next); | |
1046 | } | |
1047 | ||
1048 | /* | |
1049 | * Now construct the peer object paths in a form suitable for | |
1050 | * array_property_getter helper below. | |
1051 | */ | |
f9884c09 | 1052 | peer_obj_paths = os_calloc(num, sizeof(char *)); |
9abafccc JB |
1053 | |
1054 | if (!peer_obj_paths) { | |
1055 | out_of_mem = 1; | |
1056 | goto error; | |
1057 | } | |
1058 | ||
1059 | dl_list_for_each_safe(node, tmp, &peer_objpath_list, | |
1060 | struct peer_objpath_node, list) | |
1061 | peer_obj_paths[i++] = node->path; | |
1062 | ||
6aeeb6fa DW |
1063 | success = wpas_dbus_simple_array_property_getter(iter, |
1064 | DBUS_TYPE_OBJECT_PATH, | |
1065 | peer_obj_paths, num, | |
1066 | error); | |
9abafccc JB |
1067 | |
1068 | error: | |
1069 | if (peer_obj_paths) | |
1070 | os_free(peer_obj_paths); | |
1071 | ||
1072 | dl_list_for_each_safe(node, tmp, &peer_objpath_list, | |
1073 | struct peer_objpath_node, list) { | |
1074 | dl_list_del(&node->list); | |
1075 | os_free(node); | |
1076 | } | |
1077 | if (out_of_mem) | |
6aeeb6fa | 1078 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); |
9abafccc | 1079 | |
6aeeb6fa | 1080 | return success; |
9abafccc JB |
1081 | } |
1082 | ||
f94a85ee | 1083 | |
9abafccc JB |
1084 | enum wpas_p2p_role { |
1085 | WPAS_P2P_ROLE_DEVICE, | |
1086 | WPAS_P2P_ROLE_GO, | |
1087 | WPAS_P2P_ROLE_CLIENT, | |
1088 | }; | |
1089 | ||
1090 | static enum wpas_p2p_role wpas_get_p2p_role(struct wpa_supplicant *wpa_s) | |
1091 | { | |
1092 | struct wpa_ssid *ssid = wpa_s->current_ssid; | |
1093 | ||
1094 | if (!ssid) | |
1095 | return WPAS_P2P_ROLE_DEVICE; | |
1096 | if (wpa_s->wpa_state != WPA_COMPLETED) | |
1097 | return WPAS_P2P_ROLE_DEVICE; | |
1098 | ||
1099 | switch (ssid->mode) { | |
1100 | case WPAS_MODE_P2P_GO: | |
1101 | case WPAS_MODE_P2P_GROUP_FORMATION: | |
1102 | return WPAS_P2P_ROLE_GO; | |
1103 | case WPAS_MODE_INFRA: | |
1104 | if (ssid->p2p_group) | |
1105 | return WPAS_P2P_ROLE_CLIENT; | |
1106 | return WPAS_P2P_ROLE_DEVICE; | |
1107 | default: | |
1108 | return WPAS_P2P_ROLE_DEVICE; | |
1109 | } | |
1110 | } | |
1111 | ||
f94a85ee | 1112 | |
6aeeb6fa DW |
1113 | dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error, |
1114 | void *user_data) | |
9abafccc | 1115 | { |
6aeeb6fa | 1116 | struct wpa_supplicant *wpa_s = user_data; |
9abafccc JB |
1117 | char *str; |
1118 | ||
1119 | switch (wpas_get_p2p_role(wpa_s)) { | |
1120 | case WPAS_P2P_ROLE_GO: | |
1121 | str = "GO"; | |
1122 | break; | |
1123 | case WPAS_P2P_ROLE_CLIENT: | |
1124 | str = "client"; | |
1125 | break; | |
1126 | default: | |
1127 | str = "device"; | |
1128 | } | |
1129 | ||
6aeeb6fa DW |
1130 | return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str, |
1131 | error); | |
9abafccc JB |
1132 | } |
1133 | ||
f94a85ee | 1134 | |
6aeeb6fa DW |
1135 | dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error, |
1136 | void *user_data) | |
9abafccc | 1137 | { |
6aeeb6fa | 1138 | struct wpa_supplicant *wpa_s = user_data; |
445335fd NS |
1139 | char path_buf[WPAS_DBUS_OBJECT_PATH_MAX]; |
1140 | char *dbus_groupobj_path = path_buf; | |
6aeeb6fa | 1141 | |
9abafccc | 1142 | if (wpa_s->dbus_groupobj_path == NULL) |
445335fd NS |
1143 | os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX, |
1144 | "/"); | |
1145 | else | |
1146 | os_snprintf(dbus_groupobj_path, WPAS_DBUS_OBJECT_PATH_MAX, | |
1147 | "%s", wpa_s->dbus_groupobj_path); | |
9abafccc | 1148 | |
6aeeb6fa | 1149 | return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, |
445335fd | 1150 | &dbus_groupobj_path, error); |
9abafccc JB |
1151 | } |
1152 | ||
f94a85ee | 1153 | |
6aeeb6fa DW |
1154 | dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter, |
1155 | DBusError *error, void *user_data) | |
9abafccc | 1156 | { |
6aeeb6fa | 1157 | struct wpa_supplicant *wpa_s = user_data; |
9abafccc JB |
1158 | char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path; |
1159 | ||
1160 | if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT) | |
445335fd NS |
1161 | os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/"); |
1162 | else | |
1163 | os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, | |
1164 | "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" | |
1165 | COMPACT_MACSTR, | |
1166 | wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr)); | |
9abafccc | 1167 | |
9abafccc | 1168 | path = go_peer_obj_path; |
6aeeb6fa DW |
1169 | return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH, |
1170 | &path, error); | |
9abafccc JB |
1171 | } |
1172 | ||
f94a85ee | 1173 | |
9abafccc JB |
1174 | /* |
1175 | * Peer object properties accessor methods | |
1176 | */ | |
1177 | ||
3f6e50ac FC |
1178 | dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter, |
1179 | DBusError *error, | |
1180 | void *user_data) | |
9abafccc | 1181 | { |
6aeeb6fa | 1182 | struct peer_handler_args *peer_args = user_data; |
3f6e50ac FC |
1183 | const struct p2p_peer_info *info; |
1184 | char *tmp; | |
9abafccc | 1185 | |
e9ae4059 DW |
1186 | if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error)) |
1187 | return FALSE; | |
1188 | ||
9abafccc JB |
1189 | /* get the peer info */ |
1190 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1191 | peer_args->p2p_device_addr, 0); | |
6aeeb6fa | 1192 | if (info == NULL) { |
3f6e50ac FC |
1193 | dbus_set_error(error, DBUS_ERROR_FAILED, |
1194 | "failed to find peer"); | |
6aeeb6fa DW |
1195 | return FALSE; |
1196 | } | |
9abafccc | 1197 | |
3f6e50ac FC |
1198 | tmp = os_strdup(info->device_name); |
1199 | if (!tmp) { | |
1200 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1201 | return FALSE; | |
1202 | } | |
9abafccc | 1203 | |
3f6e50ac FC |
1204 | if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &tmp, |
1205 | error)) { | |
1206 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1207 | os_free(tmp); | |
1208 | return FALSE; | |
1209 | } | |
1210 | ||
1211 | os_free(tmp); | |
1212 | return TRUE; | |
1213 | } | |
1214 | ||
1215 | ||
1216 | dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type( | |
1217 | DBusMessageIter *iter, DBusError *error, void *user_data) | |
1218 | { | |
1219 | struct peer_handler_args *peer_args = user_data; | |
1220 | const struct p2p_peer_info *info; | |
1221 | ||
1222 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1223 | peer_args->p2p_device_addr, 0); | |
1224 | if (info == NULL) { | |
1225 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1226 | "failed to find peer"); | |
1227 | return FALSE; | |
1228 | } | |
1229 | ||
1230 | if (!wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, | |
1231 | (char *) | |
1232 | info->pri_dev_type, | |
1233 | WPS_DEV_TYPE_LEN, error)) { | |
1234 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1235 | return FALSE; | |
1236 | } | |
1237 | ||
1238 | return TRUE; | |
1239 | } | |
1240 | ||
1241 | ||
1242 | dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter, | |
1243 | DBusError *error, | |
1244 | void *user_data) | |
1245 | { | |
1246 | struct peer_handler_args *peer_args = user_data; | |
1247 | const struct p2p_peer_info *info; | |
1248 | ||
1249 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1250 | peer_args->p2p_device_addr, 0); | |
1251 | if (info == NULL) { | |
1252 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1253 | "failed to find peer"); | |
1254 | return FALSE; | |
1255 | } | |
1256 | ||
1257 | if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, | |
1258 | &info->config_methods, error)) { | |
1259 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1260 | return FALSE; | |
1261 | } | |
1262 | ||
1263 | return TRUE; | |
1264 | } | |
1265 | ||
1266 | ||
1267 | dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter, | |
1268 | DBusError *error, | |
1269 | void *user_data) | |
1270 | { | |
1271 | struct peer_handler_args *peer_args = user_data; | |
1272 | const struct p2p_peer_info *info; | |
1273 | ||
1274 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1275 | peer_args->p2p_device_addr, 0); | |
1276 | if (info == NULL) { | |
1277 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1278 | "failed to find peer"); | |
1279 | return FALSE; | |
1280 | } | |
1281 | ||
1282 | if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32, | |
1283 | &info->level, error)) { | |
1284 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1285 | return FALSE; | |
1286 | } | |
1287 | ||
1288 | return TRUE; | |
1289 | } | |
1290 | ||
1291 | ||
1292 | dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter, | |
1293 | DBusError *error, | |
1294 | void *user_data) | |
1295 | { | |
1296 | struct peer_handler_args *peer_args = user_data; | |
1297 | const struct p2p_peer_info *info; | |
1298 | ||
1299 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1300 | peer_args->p2p_device_addr, 0); | |
1301 | if (info == NULL) { | |
1302 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1303 | "failed to find peer"); | |
1304 | return FALSE; | |
1305 | } | |
1306 | ||
1307 | if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE, | |
1308 | &info->dev_capab, error)) { | |
1309 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1310 | return FALSE; | |
1311 | } | |
1312 | ||
1313 | return TRUE; | |
1314 | } | |
1315 | ||
1316 | ||
1317 | dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter, | |
1318 | DBusError *error, | |
1319 | void *user_data) | |
1320 | { | |
1321 | struct peer_handler_args *peer_args = user_data; | |
1322 | const struct p2p_peer_info *info; | |
1323 | ||
1324 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1325 | peer_args->p2p_device_addr, 0); | |
1326 | if (info == NULL) { | |
1327 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1328 | "failed to find peer"); | |
1329 | return FALSE; | |
1330 | } | |
1331 | ||
1332 | if (!wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BYTE, | |
1333 | &info->group_capab, error)) { | |
1334 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); | |
1335 | return FALSE; | |
1336 | } | |
1337 | ||
1338 | return TRUE; | |
1339 | } | |
1340 | ||
1341 | ||
1342 | dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types( | |
1343 | DBusMessageIter *iter, DBusError *error, void *user_data) | |
1344 | { | |
1345 | struct peer_handler_args *peer_args = user_data; | |
1346 | const struct p2p_peer_info *info; | |
ca298427 | 1347 | DBusMessageIter variant_iter, array_iter; |
3f6e50ac FC |
1348 | |
1349 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1350 | peer_args->p2p_device_addr, 0); | |
1351 | if (info == NULL) { | |
1352 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1353 | "failed to find peer"); | |
1354 | return FALSE; | |
1355 | } | |
9abafccc | 1356 | |
ca298427 RC |
1357 | if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, |
1358 | DBUS_TYPE_ARRAY_AS_STRING | |
1359 | DBUS_TYPE_ARRAY_AS_STRING | |
1360 | DBUS_TYPE_BYTE_AS_STRING, | |
1361 | &variant_iter)) { | |
1362 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1363 | "%s: failed to construct message 1", __func__); | |
1364 | return FALSE; | |
1365 | } | |
1366 | ||
1367 | if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, | |
1368 | DBUS_TYPE_ARRAY_AS_STRING | |
1369 | DBUS_TYPE_BYTE_AS_STRING, | |
1370 | &array_iter)) { | |
1371 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1372 | "%s: failed to construct message 2", __func__); | |
1373 | return FALSE; | |
1374 | } | |
1375 | ||
9abafccc | 1376 | if (info->wps_sec_dev_type_list_len) { |
e261d5a9 | 1377 | const u8 *sec_dev_type_list = info->wps_sec_dev_type_list; |
ca298427 RC |
1378 | int num_sec_device_types = |
1379 | info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; | |
1380 | int i; | |
1381 | DBusMessageIter inner_array_iter; | |
1382 | ||
1383 | for (i = 0; i < num_sec_device_types; i++) { | |
1384 | if (!dbus_message_iter_open_container( | |
1385 | &array_iter, DBUS_TYPE_ARRAY, | |
1386 | DBUS_TYPE_BYTE_AS_STRING, | |
1387 | &inner_array_iter)) { | |
1388 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1389 | "%s: failed to construct " | |
1390 | "message 3 (%d)", | |
1391 | __func__, i); | |
1392 | return FALSE; | |
1393 | } | |
9abafccc | 1394 | |
ca298427 RC |
1395 | if (!dbus_message_iter_append_fixed_array( |
1396 | &inner_array_iter, DBUS_TYPE_BYTE, | |
1397 | &sec_dev_type_list, WPS_DEV_TYPE_LEN)) { | |
1398 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1399 | "%s: failed to construct " | |
1400 | "message 4 (%d)", | |
1401 | __func__, i); | |
1402 | return FALSE; | |
1403 | } | |
1404 | ||
1405 | if (!dbus_message_iter_close_container( | |
1406 | &array_iter, &inner_array_iter)) { | |
1407 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1408 | "%s: failed to construct " | |
1409 | "message 5 (%d)", | |
1410 | __func__, i); | |
1411 | return FALSE; | |
1412 | } | |
1413 | ||
1414 | sec_dev_type_list += WPS_DEV_TYPE_LEN; | |
1415 | } | |
3f6e50ac FC |
1416 | } |
1417 | ||
ca298427 RC |
1418 | if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) { |
1419 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1420 | "%s: failed to construct message 6", __func__); | |
1421 | return FALSE; | |
1422 | } | |
3f6e50ac | 1423 | |
ca298427 RC |
1424 | if (!dbus_message_iter_close_container(iter, &variant_iter)) { |
1425 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1426 | "%s: failed to construct message 7", __func__); | |
1427 | return FALSE; | |
1428 | } | |
3f6e50ac | 1429 | |
ca298427 | 1430 | return TRUE; |
3f6e50ac FC |
1431 | } |
1432 | ||
1433 | ||
1434 | dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter, | |
1435 | DBusError *error, | |
1436 | void *user_data) | |
1437 | { | |
ca298427 | 1438 | struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT]; |
3f6e50ac FC |
1439 | int i, num; |
1440 | struct peer_handler_args *peer_args = user_data; | |
1441 | const struct p2p_peer_info *info; | |
1442 | ||
1443 | info = p2p_get_peer_found(peer_args->wpa_s->global->p2p, | |
1444 | peer_args->p2p_device_addr, 0); | |
1445 | if (info == NULL) { | |
1446 | dbus_set_error(error, DBUS_ERROR_FAILED, | |
1447 | "failed to find peer"); | |
1448 | return FALSE; | |
9abafccc JB |
1449 | } |
1450 | ||
f94a85ee JM |
1451 | /* Add WPS vendor extensions attribute */ |
1452 | for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) { | |
1453 | if (info->wps_vendor_ext[i] == NULL) | |
1454 | continue; | |
1455 | vendor_extension[num] = info->wps_vendor_ext[i]; | |
1456 | num++; | |
9abafccc JB |
1457 | } |
1458 | ||
ca298427 RC |
1459 | if (!wpas_dbus_simple_array_array_property_getter(iter, DBUS_TYPE_BYTE, |
1460 | vendor_extension, | |
1461 | num, error)) | |
3f6e50ac | 1462 | return FALSE; |
9abafccc | 1463 | |
6aeeb6fa | 1464 | return TRUE; |
9abafccc JB |
1465 | } |
1466 | ||
f94a85ee | 1467 | |
6aeeb6fa DW |
1468 | dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter, |
1469 | DBusError *error, void *user_data) | |
9abafccc | 1470 | { |
93d1749f | 1471 | dbus_bool_t success; |
6aeeb6fa DW |
1472 | /* struct peer_handler_args *peer_args = user_data; */ |
1473 | ||
93d1749f RC |
1474 | success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, |
1475 | NULL, 0, error); | |
1476 | return success; | |
9abafccc JB |
1477 | } |
1478 | ||
1479 | ||
c2762e41 | 1480 | /** |
ffbf1eaa | 1481 | * wpas_dbus_getter_persistent_groups - Get array of persistent group objects |
6aeeb6fa DW |
1482 | * @iter: Pointer to incoming dbus message iter |
1483 | * @error: Location to store error on failure | |
1484 | * @user_data: Function specific data | |
1485 | * Returns: TRUE on success, FALSE on failure | |
c2762e41 | 1486 | * |
6aeeb6fa | 1487 | * Getter for "PersistentGroups" property. |
c2762e41 | 1488 | */ |
6aeeb6fa DW |
1489 | dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter, |
1490 | DBusError *error, | |
1491 | void *user_data) | |
c2762e41 | 1492 | { |
6aeeb6fa | 1493 | struct wpa_supplicant *wpa_s = user_data; |
c2762e41 JS |
1494 | struct wpa_ssid *ssid; |
1495 | char **paths; | |
1496 | unsigned int i = 0, num = 0; | |
6aeeb6fa | 1497 | dbus_bool_t success = FALSE; |
c2762e41 JS |
1498 | |
1499 | if (wpa_s->conf == NULL) { | |
28550706 JS |
1500 | wpa_printf(MSG_ERROR, "dbus: %s: " |
1501 | "An error occurred getting persistent groups list", | |
1502 | __func__); | |
6aeeb6fa DW |
1503 | dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error " |
1504 | "occurred getting persistent groups list"); | |
1505 | return FALSE; | |
c2762e41 JS |
1506 | } |
1507 | ||
1508 | for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) | |
1509 | if (network_is_persistent_group(ssid)) | |
1510 | num++; | |
1511 | ||
f9884c09 | 1512 | paths = os_calloc(num, sizeof(char *)); |
c2762e41 | 1513 | if (!paths) { |
6aeeb6fa DW |
1514 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); |
1515 | return FALSE; | |
c2762e41 JS |
1516 | } |
1517 | ||
1518 | /* Loop through configured networks and append object path of each */ | |
1519 | for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { | |
1520 | if (!network_is_persistent_group(ssid)) | |
1521 | continue; | |
1522 | paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); | |
1523 | if (paths[i] == NULL) { | |
6aeeb6fa DW |
1524 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, |
1525 | "no memory"); | |
c2762e41 JS |
1526 | goto out; |
1527 | } | |
1528 | /* Construct the object path for this network. */ | |
1529 | os_snprintf(paths[i++], WPAS_DBUS_OBJECT_PATH_MAX, | |
1530 | "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", | |
1531 | wpa_s->dbus_new_path, ssid->id); | |
1532 | } | |
1533 | ||
6aeeb6fa DW |
1534 | success = wpas_dbus_simple_array_property_getter(iter, |
1535 | DBUS_TYPE_OBJECT_PATH, | |
1536 | paths, num, error); | |
c2762e41 JS |
1537 | |
1538 | out: | |
1539 | while (i) | |
1540 | os_free(paths[--i]); | |
1541 | os_free(paths); | |
6aeeb6fa | 1542 | return success; |
c2762e41 JS |
1543 | } |
1544 | ||
1545 | ||
1546 | /** | |
1547 | * wpas_dbus_getter_persistent_group_properties - Get options for a persistent | |
1548 | * group | |
6aeeb6fa DW |
1549 | * @iter: Pointer to incoming dbus message iter |
1550 | * @error: Location to store error on failure | |
1551 | * @user_data: Function specific data | |
1552 | * Returns: TRUE on success, FALSE on failure | |
c2762e41 JS |
1553 | * |
1554 | * Getter for "Properties" property of a persistent group. | |
1555 | */ | |
6aeeb6fa DW |
1556 | dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter, |
1557 | DBusError *error, | |
1558 | void *user_data) | |
c2762e41 | 1559 | { |
6aeeb6fa DW |
1560 | struct network_handler_args *net = user_data; |
1561 | ||
1562 | /* Leveraging the fact that persistent group object is still | |
c2762e41 JS |
1563 | * represented in same manner as network within. |
1564 | */ | |
6aeeb6fa | 1565 | return wpas_dbus_getter_network_properties(iter, error, net); |
c2762e41 JS |
1566 | } |
1567 | ||
1568 | ||
28550706 JS |
1569 | /** |
1570 | * wpas_dbus_setter_persistent_group_properties - Get options for a persistent | |
1571 | * group | |
6aeeb6fa DW |
1572 | * @iter: Pointer to incoming dbus message iter |
1573 | * @error: Location to store error on failure | |
1574 | * @user_data: Function specific data | |
1575 | * Returns: TRUE on success, FALSE on failure | |
28550706 JS |
1576 | * |
1577 | * Setter for "Properties" property of a persistent group. | |
1578 | */ | |
6aeeb6fa DW |
1579 | dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter, |
1580 | DBusError *error, | |
1581 | void *user_data) | |
28550706 | 1582 | { |
6aeeb6fa | 1583 | struct network_handler_args *net = user_data; |
28550706 | 1584 | struct wpa_ssid *ssid = net->ssid; |
6aeeb6fa | 1585 | DBusMessageIter variant_iter; |
28550706 JS |
1586 | |
1587 | /* | |
1588 | * Leveraging the fact that persistent group object is still | |
1589 | * represented in same manner as network within. | |
1590 | */ | |
6aeeb6fa DW |
1591 | dbus_message_iter_recurse(iter, &variant_iter); |
1592 | return set_network_properties(net->wpa_s, ssid, &variant_iter, error); | |
28550706 JS |
1593 | } |
1594 | ||
1595 | ||
1596 | /** | |
1597 | * wpas_dbus_new_iface_add_persistent_group - Add a new configured | |
1598 | * persistent_group | |
1599 | * @message: Pointer to incoming dbus message | |
1600 | * @wpa_s: wpa_supplicant structure for a network interface | |
1601 | * Returns: A dbus message containing the object path of the new | |
1602 | * persistent group | |
1603 | * | |
1604 | * Handler function for "AddPersistentGroup" method call of a P2P Device | |
1605 | * interface. | |
1606 | */ | |
1607 | DBusMessage * wpas_dbus_handler_add_persistent_group( | |
1608 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
1609 | { | |
1610 | DBusMessage *reply = NULL; | |
1611 | DBusMessageIter iter; | |
1612 | struct wpa_ssid *ssid = NULL; | |
1613 | char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf; | |
6aeeb6fa | 1614 | DBusError error; |
28550706 JS |
1615 | |
1616 | dbus_message_iter_init(message, &iter); | |
1617 | ||
1618 | ssid = wpa_config_add_network(wpa_s->conf); | |
1619 | if (ssid == NULL) { | |
1620 | wpa_printf(MSG_ERROR, "dbus: %s: " | |
1621 | "Cannot add new persistent group", __func__); | |
1622 | reply = wpas_dbus_error_unknown_error( | |
1623 | message, | |
1624 | "wpa_supplicant could not add " | |
1625 | "a persistent group on this interface."); | |
1626 | goto err; | |
1627 | } | |
1628 | ||
1629 | /* Mark the ssid as being a persistent group before the notification */ | |
1630 | ssid->disabled = 2; | |
1631 | ssid->p2p_persistent_group = 1; | |
1632 | wpas_notify_persistent_group_added(wpa_s, ssid); | |
1633 | ||
1634 | wpa_config_set_network_defaults(ssid); | |
1635 | ||
6aeeb6fa DW |
1636 | dbus_error_init(&error); |
1637 | if (!set_network_properties(wpa_s, ssid, &iter, &error)) { | |
28550706 JS |
1638 | wpa_printf(MSG_DEBUG, "dbus: %s: " |
1639 | "Control interface could not set persistent group " | |
1640 | "properties", __func__); | |
6aeeb6fa DW |
1641 | reply = wpas_dbus_reply_new_from_error(message, &error, |
1642 | DBUS_ERROR_INVALID_ARGS, | |
1643 | "Failed to set network " | |
1644 | "properties"); | |
1645 | dbus_error_free(&error); | |
28550706 JS |
1646 | goto err; |
1647 | } | |
1648 | ||
1649 | /* Construct the object path for this network. */ | |
1650 | os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX, | |
1651 | "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%d", | |
1652 | wpa_s->dbus_new_path, ssid->id); | |
1653 | ||
1654 | reply = dbus_message_new_method_return(message); | |
1655 | if (reply == NULL) { | |
1656 | reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, | |
1657 | NULL); | |
1658 | goto err; | |
1659 | } | |
1660 | if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, | |
1661 | DBUS_TYPE_INVALID)) { | |
1662 | dbus_message_unref(reply); | |
1663 | reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, | |
1664 | NULL); | |
1665 | goto err; | |
1666 | } | |
1667 | ||
1668 | return reply; | |
1669 | ||
1670 | err: | |
1671 | if (ssid) { | |
1672 | wpas_notify_persistent_group_removed(wpa_s, ssid); | |
1673 | wpa_config_remove_network(wpa_s->conf, ssid->id); | |
1674 | } | |
1675 | return reply; | |
1676 | } | |
1677 | ||
1678 | ||
1679 | /** | |
1680 | * wpas_dbus_handler_remove_persistent_group - Remove a configured persistent | |
1681 | * group | |
1682 | * @message: Pointer to incoming dbus message | |
1683 | * @wpa_s: wpa_supplicant structure for a network interface | |
1684 | * Returns: NULL on success or dbus error on failure | |
1685 | * | |
1686 | * Handler function for "RemovePersistentGroup" method call of a P2P Device | |
1687 | * interface. | |
1688 | */ | |
1689 | DBusMessage * wpas_dbus_handler_remove_persistent_group( | |
1690 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
1691 | { | |
1692 | DBusMessage *reply = NULL; | |
1693 | const char *op; | |
1694 | char *iface = NULL, *persistent_group_id = NULL; | |
1695 | int id; | |
1696 | struct wpa_ssid *ssid; | |
1697 | ||
1698 | dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op, | |
1699 | DBUS_TYPE_INVALID); | |
1700 | ||
1701 | /* | |
1702 | * Extract the network ID and ensure the network is actually a child of | |
1703 | * this interface. | |
1704 | */ | |
1705 | iface = wpas_dbus_new_decompose_object_path(op, 1, | |
1706 | &persistent_group_id, | |
1707 | NULL); | |
1708 | if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) { | |
1709 | reply = wpas_dbus_error_invalid_args(message, op); | |
1710 | goto out; | |
1711 | } | |
1712 | ||
1713 | id = strtoul(persistent_group_id, NULL, 10); | |
1714 | if (errno == EINVAL) { | |
1715 | reply = wpas_dbus_error_invalid_args(message, op); | |
1716 | goto out; | |
1717 | } | |
1718 | ||
1719 | ssid = wpa_config_get_network(wpa_s->conf, id); | |
1720 | if (ssid == NULL) { | |
1721 | reply = wpas_dbus_error_persistent_group_unknown(message); | |
1722 | goto out; | |
1723 | } | |
1724 | ||
1725 | wpas_notify_persistent_group_removed(wpa_s, ssid); | |
1726 | ||
1727 | if (wpa_config_remove_network(wpa_s->conf, id) < 0) { | |
1728 | wpa_printf(MSG_ERROR, "dbus: %s: " | |
1729 | "error occurred when removing persistent group %d", | |
1730 | __func__, id); | |
1731 | reply = wpas_dbus_error_unknown_error( | |
1732 | message, | |
1733 | "error removing the specified persistent group on " | |
1734 | "this interface."); | |
1735 | goto out; | |
1736 | } | |
1737 | ||
1738 | out: | |
1739 | os_free(iface); | |
1740 | os_free(persistent_group_id); | |
1741 | return reply; | |
1742 | } | |
1743 | ||
1744 | ||
1745 | static void remove_persistent_group(struct wpa_supplicant *wpa_s, | |
1746 | struct wpa_ssid *ssid) | |
1747 | { | |
1748 | wpas_notify_persistent_group_removed(wpa_s, ssid); | |
1749 | ||
1750 | if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) { | |
1751 | wpa_printf(MSG_ERROR, "dbus: %s: " | |
1752 | "error occurred when removing persistent group %d", | |
1753 | __func__, ssid->id); | |
1754 | return; | |
1755 | } | |
1756 | } | |
1757 | ||
1758 | ||
1759 | /** | |
1760 | * wpas_dbus_handler_remove_all_persistent_groups - Remove all configured | |
1761 | * persistent groups | |
1762 | * @message: Pointer to incoming dbus message | |
1763 | * @wpa_s: wpa_supplicant structure for a network interface | |
1764 | * Returns: NULL on success or dbus error on failure | |
1765 | * | |
1766 | * Handler function for "RemoveAllPersistentGroups" method call of a | |
1767 | * P2P Device interface. | |
1768 | */ | |
1769 | DBusMessage * wpas_dbus_handler_remove_all_persistent_groups( | |
1770 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
1771 | { | |
1772 | struct wpa_ssid *ssid, *next; | |
1773 | struct wpa_config *config; | |
1774 | ||
1775 | config = wpa_s->conf; | |
1776 | ssid = config->ssid; | |
1777 | while (ssid) { | |
1778 | next = ssid->next; | |
1779 | if (network_is_persistent_group(ssid)) | |
1780 | remove_persistent_group(wpa_s, ssid); | |
1781 | ssid = next; | |
1782 | } | |
1783 | return NULL; | |
1784 | } | |
1785 | ||
1786 | ||
9abafccc JB |
1787 | /* |
1788 | * Group object properties accessor methods | |
1789 | */ | |
1790 | ||
6aeeb6fa DW |
1791 | dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter, |
1792 | DBusError *error, | |
1793 | void *user_data) | |
9abafccc | 1794 | { |
6aeeb6fa | 1795 | struct wpa_supplicant *wpa_s = user_data; |
9abafccc JB |
1796 | struct wpa_ssid *ssid; |
1797 | unsigned int num_members; | |
1798 | char **paths; | |
1799 | unsigned int i; | |
1800 | void *next = NULL; | |
1801 | const u8 *addr; | |
6aeeb6fa | 1802 | dbus_bool_t success = FALSE; |
9abafccc | 1803 | |
7d39d9c9 TP |
1804 | /* Verify correct role for this property */ |
1805 | if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_GO) { | |
1806 | return wpas_dbus_simple_array_property_getter( | |
1807 | iter, DBUS_TYPE_OBJECT_PATH, NULL, 0, error); | |
1808 | } | |
9abafccc JB |
1809 | |
1810 | ssid = wpa_s->conf->ssid; | |
1811 | /* At present WPAS P2P_GO mode only applicable for p2p_go */ | |
1812 | if (ssid->mode != WPAS_MODE_P2P_GO && | |
1813 | ssid->mode != WPAS_MODE_AP && | |
1814 | ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION) | |
6aeeb6fa | 1815 | return FALSE; |
9abafccc JB |
1816 | |
1817 | num_members = p2p_get_group_num_members(wpa_s->p2p_group); | |
1818 | ||
f9884c09 | 1819 | paths = os_calloc(num_members, sizeof(char *)); |
9abafccc JB |
1820 | if (!paths) |
1821 | goto out_of_memory; | |
1822 | ||
1823 | i = 0; | |
1824 | while ((addr = p2p_iterate_group_members(wpa_s->p2p_group, &next))) { | |
1825 | paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX); | |
1826 | if (!paths[i]) | |
1827 | goto out_of_memory; | |
1828 | os_snprintf(paths[i], WPAS_DBUS_OBJECT_PATH_MAX, | |
1829 | "%s/" WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART | |
1830 | "/" COMPACT_MACSTR, | |
1831 | wpa_s->dbus_groupobj_path, MAC2STR(addr)); | |
1832 | i++; | |
1833 | } | |
1834 | ||
6aeeb6fa DW |
1835 | success = wpas_dbus_simple_array_property_getter(iter, |
1836 | DBUS_TYPE_OBJECT_PATH, | |
1837 | paths, num_members, | |
1838 | error); | |
9abafccc | 1839 | |
9abafccc JB |
1840 | for (i = 0; i < num_members; i++) |
1841 | os_free(paths[i]); | |
1842 | os_free(paths); | |
6aeeb6fa | 1843 | return success; |
faa9f2cf | 1844 | |
9abafccc | 1845 | out_of_memory: |
6aeeb6fa | 1846 | dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory"); |
faa9f2cf JM |
1847 | if (paths) { |
1848 | for (i = 0; i < num_members; i++) | |
1849 | os_free(paths[i]); | |
1850 | os_free(paths); | |
1851 | } | |
6aeeb6fa | 1852 | return FALSE; |
9abafccc JB |
1853 | } |
1854 | ||
1855 | ||
7d39d9c9 TP |
1856 | dbus_bool_t wpas_dbus_getter_p2p_group_ssid(DBusMessageIter *iter, |
1857 | DBusError *error, void *user_data) | |
1858 | { | |
1859 | struct wpa_supplicant *wpa_s = user_data; | |
1860 | if (wpa_s->current_ssid == NULL) | |
1861 | return FALSE; | |
1862 | return wpas_dbus_simple_array_property_getter( | |
1863 | iter, DBUS_TYPE_BYTE, wpa_s->current_ssid->ssid, | |
1864 | wpa_s->current_ssid->ssid_len, error); | |
1865 | } | |
1866 | ||
1867 | ||
1868 | dbus_bool_t wpas_dbus_getter_p2p_group_bssid(DBusMessageIter *iter, | |
1869 | DBusError *error, | |
1870 | void *user_data) | |
9abafccc | 1871 | { |
6aeeb6fa | 1872 | struct wpa_supplicant *wpa_s = user_data; |
aa89df56 | 1873 | u8 role = wpas_get_p2p_role(wpa_s); |
7d39d9c9 | 1874 | u8 *p_bssid; |
9abafccc | 1875 | |
7d39d9c9 TP |
1876 | if (role == WPAS_P2P_ROLE_CLIENT) { |
1877 | if (wpa_s->current_ssid == NULL) | |
1878 | return FALSE; | |
1879 | p_bssid = wpa_s->current_ssid->bssid; | |
1880 | } else { | |
1881 | if (wpa_s->ap_iface == NULL) | |
1882 | return FALSE; | |
1883 | p_bssid = wpa_s->ap_iface->bss[0]->own_addr; | |
1884 | } | |
aa89df56 | 1885 | |
7d39d9c9 TP |
1886 | return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, |
1887 | p_bssid, ETH_ALEN, | |
1888 | error); | |
1889 | } | |
1890 | ||
1891 | ||
1892 | dbus_bool_t wpas_dbus_getter_p2p_group_frequency(DBusMessageIter *iter, | |
1893 | DBusError *error, | |
1894 | void *user_data) | |
1895 | { | |
1896 | struct wpa_supplicant *wpa_s = user_data; | |
1897 | u16 op_freq; | |
1898 | u8 role = wpas_get_p2p_role(wpa_s); | |
1899 | ||
1900 | if (role == WPAS_P2P_ROLE_CLIENT) { | |
1901 | if (wpa_s->go_params == NULL) | |
aa89df56 | 1902 | return FALSE; |
7d39d9c9 TP |
1903 | op_freq = wpa_s->go_params->freq; |
1904 | } else { | |
1905 | if (wpa_s->ap_iface == NULL) | |
aa89df56 | 1906 | return FALSE; |
7d39d9c9 | 1907 | op_freq = wpa_s->ap_iface->freq; |
9abafccc JB |
1908 | } |
1909 | ||
7d39d9c9 TP |
1910 | return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16, |
1911 | &op_freq, error); | |
1912 | } | |
1913 | ||
9abafccc | 1914 | |
7d39d9c9 TP |
1915 | dbus_bool_t wpas_dbus_getter_p2p_group_passphrase(DBusMessageIter *iter, |
1916 | DBusError *error, | |
1917 | void *user_data) | |
1918 | { | |
1919 | struct wpa_supplicant *wpa_s = user_data; | |
1920 | u8 role = wpas_get_p2p_role(wpa_s); | |
1921 | char *p_pass = NULL; | |
1922 | ||
1923 | /* Verify correct role for this property */ | |
aa89df56 | 1924 | if (role == WPAS_P2P_ROLE_GO) { |
7d39d9c9 TP |
1925 | if (wpa_s->current_ssid == NULL) |
1926 | return FALSE; | |
1927 | p_pass = wpa_s->current_ssid->passphrase; | |
1928 | } else | |
1929 | p_pass = ""; | |
1930 | ||
1931 | return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, | |
1932 | &p_pass, error); | |
1933 | ||
1934 | } | |
1935 | ||
1936 | ||
1937 | dbus_bool_t wpas_dbus_getter_p2p_group_psk(DBusMessageIter *iter, | |
1938 | DBusError *error, void *user_data) | |
1939 | { | |
1940 | struct wpa_supplicant *wpa_s = user_data; | |
1941 | u8 role = wpas_get_p2p_role(wpa_s); | |
1942 | u8 *p_psk = NULL; | |
1943 | u8 psk_len = 0; | |
1944 | ||
1945 | /* Verify correct role for this property */ | |
1946 | if (role == WPAS_P2P_ROLE_CLIENT) { | |
1947 | if (wpa_s->current_ssid == NULL) | |
1948 | return FALSE; | |
1949 | p_psk = wpa_s->current_ssid->psk; | |
1950 | psk_len = 32; | |
1951 | } | |
1952 | ||
1953 | return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE, | |
1954 | &p_psk, psk_len, error); | |
1955 | } | |
1956 | ||
1957 | ||
1958 | dbus_bool_t wpas_dbus_getter_p2p_group_vendor_ext(DBusMessageIter *iter, | |
1959 | DBusError *error, | |
1960 | void *user_data) | |
1961 | { | |
1962 | struct wpa_supplicant *wpa_s = user_data; | |
1963 | struct hostapd_data *hapd; | |
1964 | struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS]; | |
1965 | int num_vendor_ext = 0; | |
1966 | int i; | |
1967 | ||
1968 | /* Verify correct role for this property */ | |
1969 | if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO) { | |
1970 | if (wpa_s->ap_iface == NULL) | |
1971 | return FALSE; | |
1972 | hapd = wpa_s->ap_iface->bss[0]; | |
1973 | ||
aa89df56 | 1974 | /* Parse WPS Vendor Extensions sent in Beacon/Probe Response */ |
7d39d9c9 | 1975 | for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { |
aa89df56 | 1976 | if (hapd->conf->wps_vendor_ext[i] == NULL) |
7d39d9c9 TP |
1977 | vendor_ext[i] = NULL; |
1978 | else { | |
1979 | vendor_ext[num_vendor_ext++] = | |
1980 | hapd->conf->wps_vendor_ext[i]; | |
1981 | } | |
aa89df56 | 1982 | } |
9abafccc JB |
1983 | } |
1984 | ||
7d39d9c9 TP |
1985 | /* Return vendor extensions or no data */ |
1986 | return wpas_dbus_simple_array_array_property_getter(iter, | |
1987 | DBUS_TYPE_BYTE, | |
1988 | vendor_ext, | |
1989 | num_vendor_ext, | |
1990 | error); | |
9abafccc JB |
1991 | } |
1992 | ||
f94a85ee | 1993 | |
7d39d9c9 | 1994 | dbus_bool_t wpas_dbus_setter_p2p_group_vendor_ext(DBusMessageIter *iter, |
6aeeb6fa DW |
1995 | DBusError *error, |
1996 | void *user_data) | |
9abafccc | 1997 | { |
6aeeb6fa DW |
1998 | struct wpa_supplicant *wpa_s = user_data; |
1999 | DBusMessageIter variant_iter, iter_dict; | |
f94a85ee | 2000 | struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING }; |
9abafccc | 2001 | unsigned int i; |
4bb70bd8 | 2002 | struct hostapd_data *hapd = NULL; |
9abafccc | 2003 | |
4bb70bd8 TP |
2004 | if (wpas_get_p2p_role(wpa_s) == WPAS_P2P_ROLE_GO && |
2005 | wpa_s->ap_iface != NULL) | |
2006 | hapd = wpa_s->ap_iface->bss[0]; | |
2007 | else | |
6aeeb6fa | 2008 | return FALSE; |
9abafccc | 2009 | |
6aeeb6fa DW |
2010 | dbus_message_iter_recurse(iter, &variant_iter); |
2011 | if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error)) | |
2012 | return FALSE; | |
9abafccc JB |
2013 | |
2014 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
2015 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) { | |
6aeeb6fa DW |
2016 | dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, |
2017 | "invalid message format"); | |
2018 | return FALSE; | |
9abafccc JB |
2019 | } |
2020 | ||
2021 | if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) { | |
2022 | if (entry.type != DBUS_TYPE_ARRAY || | |
2023 | entry.array_type != WPAS_DBUS_TYPE_BINARRAY || | |
2024 | entry.array_len > MAX_WPS_VENDOR_EXTENSIONS) | |
2025 | goto error; | |
2026 | ||
2027 | for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) { | |
2028 | if (i < entry.array_len) { | |
2029 | hapd->conf->wps_vendor_ext[i] = | |
2030 | entry.binarray_value[i]; | |
2031 | entry.binarray_value[i] = NULL; | |
2032 | } else | |
2033 | hapd->conf->wps_vendor_ext[i] = NULL; | |
2034 | } | |
2035 | ||
2036 | hostapd_update_wps(hapd); | |
2037 | } else | |
2038 | goto error; | |
2039 | ||
2040 | wpa_dbus_dict_entry_clear(&entry); | |
2041 | } | |
2042 | ||
6aeeb6fa | 2043 | return TRUE; |
9abafccc JB |
2044 | |
2045 | error: | |
9abafccc | 2046 | wpa_dbus_dict_entry_clear(&entry); |
6aeeb6fa DW |
2047 | dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS, |
2048 | "invalid message format"); | |
2049 | return FALSE; | |
9abafccc JB |
2050 | } |
2051 | ||
f94a85ee JM |
2052 | |
2053 | DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message, | |
2054 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2055 | { |
2056 | DBusMessageIter iter_dict; | |
2057 | DBusMessage *reply = NULL; | |
2058 | DBusMessageIter iter; | |
2059 | struct wpa_dbus_dict_entry entry; | |
2060 | int upnp = 0; | |
2061 | int bonjour = 0; | |
2062 | char *service = NULL; | |
2063 | struct wpabuf *query = NULL; | |
2064 | struct wpabuf *resp = NULL; | |
2065 | u8 version = 0; | |
2066 | ||
2067 | dbus_message_iter_init(message, &iter); | |
2068 | ||
6aeeb6fa | 2069 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
2070 | goto error; |
2071 | ||
c9b72c25 | 2072 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { |
9abafccc JB |
2073 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) |
2074 | goto error; | |
2075 | ||
f94a85ee | 2076 | if (!os_strcmp(entry.key, "service_type") && |
9abafccc | 2077 | (entry.type == DBUS_TYPE_STRING)) { |
f94a85ee | 2078 | if (!os_strcmp(entry.str_value, "upnp")) |
9abafccc | 2079 | upnp = 1; |
f94a85ee | 2080 | else if (!os_strcmp(entry.str_value, "bonjour")) |
9abafccc JB |
2081 | bonjour = 1; |
2082 | else | |
2083 | goto error_clear; | |
c9b72c25 AB |
2084 | } else if (!os_strcmp(entry.key, "version") && |
2085 | entry.type == DBUS_TYPE_INT32) { | |
2086 | version = entry.uint32_value; | |
2087 | } else if (!os_strcmp(entry.key, "service") && | |
2088 | (entry.type == DBUS_TYPE_STRING)) { | |
2089 | service = os_strdup(entry.str_value); | |
2090 | } else if (!os_strcmp(entry.key, "query")) { | |
2091 | if ((entry.type != DBUS_TYPE_ARRAY) || | |
2092 | (entry.array_type != DBUS_TYPE_BYTE)) | |
2093 | goto error_clear; | |
2094 | query = wpabuf_alloc_copy( | |
2095 | entry.bytearray_value, | |
2096 | entry.array_len); | |
2097 | } else if (!os_strcmp(entry.key, "response")) { | |
2098 | if ((entry.type != DBUS_TYPE_ARRAY) || | |
2099 | (entry.array_type != DBUS_TYPE_BYTE)) | |
2100 | goto error_clear; | |
2101 | resp = wpabuf_alloc_copy(entry.bytearray_value, | |
2102 | entry.array_len); | |
9abafccc | 2103 | } |
c9b72c25 | 2104 | wpa_dbus_dict_entry_clear(&entry); |
9abafccc JB |
2105 | } |
2106 | ||
2107 | if (upnp == 1) { | |
9abafccc JB |
2108 | if (version <= 0 || service == NULL) |
2109 | goto error; | |
2110 | ||
2111 | if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0) | |
2112 | goto error; | |
2113 | ||
2114 | os_free(service); | |
c9b72c25 | 2115 | service = NULL; |
9abafccc | 2116 | } else if (bonjour == 1) { |
9abafccc JB |
2117 | if (query == NULL || resp == NULL) |
2118 | goto error; | |
2119 | ||
c9b72c25 | 2120 | if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) |
9abafccc | 2121 | goto error; |
c9b72c25 AB |
2122 | query = NULL; |
2123 | resp = NULL; | |
9abafccc JB |
2124 | } else |
2125 | goto error; | |
2126 | ||
2127 | return reply; | |
2128 | error_clear: | |
2129 | wpa_dbus_dict_entry_clear(&entry); | |
2130 | error: | |
c9b72c25 AB |
2131 | os_free(service); |
2132 | wpabuf_free(query); | |
2133 | wpabuf_free(resp); | |
9abafccc JB |
2134 | return wpas_dbus_error_invalid_args(message, NULL); |
2135 | } | |
2136 | ||
f94a85ee JM |
2137 | |
2138 | DBusMessage * wpas_dbus_handler_p2p_delete_service( | |
2139 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2140 | { |
2141 | DBusMessageIter iter_dict; | |
2142 | DBusMessage *reply = NULL; | |
2143 | DBusMessageIter iter; | |
2144 | struct wpa_dbus_dict_entry entry; | |
2145 | int upnp = 0; | |
2146 | int bonjour = 0; | |
2147 | int ret = 0; | |
2148 | char *service = NULL; | |
2149 | struct wpabuf *query = NULL; | |
2150 | u8 version = 0; | |
2151 | ||
2152 | dbus_message_iter_init(message, &iter); | |
2153 | ||
6aeeb6fa | 2154 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
2155 | goto error; |
2156 | ||
2157 | if (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
2158 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
2159 | goto error; | |
2160 | ||
f94a85ee | 2161 | if (!os_strcmp(entry.key, "service_type") && |
9abafccc | 2162 | (entry.type == DBUS_TYPE_STRING)) { |
f94a85ee | 2163 | if (!os_strcmp(entry.str_value, "upnp")) |
9abafccc | 2164 | upnp = 1; |
f94a85ee | 2165 | else if (!os_strcmp(entry.str_value, "bonjour")) |
9abafccc JB |
2166 | bonjour = 1; |
2167 | else | |
2168 | goto error_clear; | |
2169 | wpa_dbus_dict_entry_clear(&entry); | |
2170 | } | |
2171 | } | |
2172 | if (upnp == 1) { | |
2173 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
2174 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
2175 | goto error; | |
f94a85ee | 2176 | if (!os_strcmp(entry.key, "version") && |
9abafccc JB |
2177 | entry.type == DBUS_TYPE_INT32) |
2178 | version = entry.uint32_value; | |
f94a85ee | 2179 | else if (!os_strcmp(entry.key, "service") && |
9abafccc JB |
2180 | entry.type == DBUS_TYPE_STRING) |
2181 | service = os_strdup(entry.str_value); | |
2182 | else | |
2183 | goto error_clear; | |
2184 | ||
2185 | wpa_dbus_dict_entry_clear(&entry); | |
2186 | } | |
2187 | ||
2188 | if (version <= 0 || service == NULL) | |
2189 | goto error; | |
2190 | ||
2191 | ret = wpas_p2p_service_del_upnp(wpa_s, version, service); | |
2192 | os_free(service); | |
2193 | if (ret != 0) | |
2194 | goto error; | |
2195 | } else if (bonjour == 1) { | |
2196 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
2197 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
2198 | goto error; | |
2199 | ||
f94a85ee | 2200 | if (!os_strcmp(entry.key, "query")) { |
9abafccc JB |
2201 | if ((entry.type != DBUS_TYPE_ARRAY) || |
2202 | (entry.array_type != DBUS_TYPE_BYTE)) | |
2203 | goto error_clear; | |
f94a85ee JM |
2204 | query = wpabuf_alloc_copy( |
2205 | entry.bytearray_value, | |
2206 | entry.array_len); | |
9abafccc JB |
2207 | } else |
2208 | goto error_clear; | |
2209 | ||
2210 | wpa_dbus_dict_entry_clear(&entry); | |
2211 | } | |
2212 | ||
2213 | if (query == NULL) | |
2214 | goto error; | |
2215 | ||
2216 | ret = wpas_p2p_service_del_bonjour(wpa_s, query); | |
2217 | if (ret != 0) | |
2218 | goto error; | |
2219 | wpabuf_free(query); | |
2220 | } else | |
2221 | goto error; | |
2222 | ||
2223 | return reply; | |
2224 | error_clear: | |
2225 | wpa_dbus_dict_entry_clear(&entry); | |
2226 | error: | |
2227 | return wpas_dbus_error_invalid_args(message, NULL); | |
2228 | } | |
2229 | ||
f94a85ee JM |
2230 | |
2231 | DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message, | |
2232 | struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2233 | { |
2234 | wpas_p2p_service_flush(wpa_s); | |
2235 | return NULL; | |
2236 | } | |
2237 | ||
f94a85ee JM |
2238 | |
2239 | DBusMessage * wpas_dbus_handler_p2p_service_sd_req( | |
2240 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2241 | { |
2242 | DBusMessageIter iter_dict; | |
2243 | DBusMessage *reply = NULL; | |
2244 | DBusMessageIter iter; | |
2245 | struct wpa_dbus_dict_entry entry; | |
2246 | int upnp = 0; | |
2247 | char *service = NULL; | |
2248 | char *peer_object_path = NULL; | |
2249 | struct wpabuf *tlv = NULL; | |
2250 | u8 version = 0; | |
2251 | u64 ref = 0; | |
e56fc9e8 | 2252 | u8 addr_buf[ETH_ALEN], *addr; |
9abafccc JB |
2253 | |
2254 | dbus_message_iter_init(message, &iter); | |
2255 | ||
6aeeb6fa | 2256 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
2257 | goto error; |
2258 | ||
2259 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
2260 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
2261 | goto error; | |
f94a85ee | 2262 | if (!os_strcmp(entry.key, "peer_object") && |
9abafccc JB |
2263 | entry.type == DBUS_TYPE_OBJECT_PATH) { |
2264 | peer_object_path = os_strdup(entry.str_value); | |
f94a85ee | 2265 | } else if (!os_strcmp(entry.key, "service_type") && |
9abafccc | 2266 | entry.type == DBUS_TYPE_STRING) { |
f94a85ee | 2267 | if (!os_strcmp(entry.str_value, "upnp")) |
9abafccc JB |
2268 | upnp = 1; |
2269 | else | |
2270 | goto error_clear; | |
f94a85ee | 2271 | } else if (!os_strcmp(entry.key, "version") && |
9abafccc JB |
2272 | entry.type == DBUS_TYPE_INT32) { |
2273 | version = entry.uint32_value; | |
f94a85ee | 2274 | } else if (!os_strcmp(entry.key, "service") && |
9abafccc JB |
2275 | entry.type == DBUS_TYPE_STRING) { |
2276 | service = os_strdup(entry.str_value); | |
f94a85ee | 2277 | } else if (!os_strcmp(entry.key, "tlv")) { |
9abafccc JB |
2278 | if (entry.type != DBUS_TYPE_ARRAY || |
2279 | entry.array_type != DBUS_TYPE_BYTE) | |
2280 | goto error_clear; | |
2281 | tlv = wpabuf_alloc_copy(entry.bytearray_value, | |
2282 | entry.array_len); | |
2283 | } else | |
2284 | goto error_clear; | |
2285 | ||
2286 | wpa_dbus_dict_entry_clear(&entry); | |
2287 | } | |
2288 | ||
e56fc9e8 AB |
2289 | if (!peer_object_path) { |
2290 | addr = NULL; | |
2291 | } else { | |
2292 | if (parse_peer_object_path(peer_object_path, addr_buf) < 0 || | |
2293 | !p2p_peer_known(wpa_s->global->p2p, addr_buf)) | |
2294 | goto error; | |
2295 | ||
2296 | addr = addr_buf; | |
2297 | } | |
9abafccc JB |
2298 | |
2299 | if (upnp == 1) { | |
2300 | if (version <= 0 || service == NULL) | |
2301 | goto error; | |
2302 | ||
7165c5dc | 2303 | ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service); |
9abafccc JB |
2304 | } else { |
2305 | if (tlv == NULL) | |
2306 | goto error; | |
7165c5dc | 2307 | ref = wpas_p2p_sd_request(wpa_s, addr, tlv); |
9abafccc JB |
2308 | wpabuf_free(tlv); |
2309 | } | |
2310 | ||
2311 | if (ref != 0) { | |
2312 | reply = dbus_message_new_method_return(message); | |
2313 | dbus_message_append_args(reply, DBUS_TYPE_UINT64, | |
2314 | &ref, DBUS_TYPE_INVALID); | |
2315 | } else { | |
f94a85ee JM |
2316 | reply = wpas_dbus_error_unknown_error( |
2317 | message, "Unable to send SD request"); | |
9abafccc JB |
2318 | } |
2319 | out: | |
2320 | os_free(service); | |
2321 | os_free(peer_object_path); | |
2322 | return reply; | |
2323 | error_clear: | |
2324 | wpa_dbus_dict_entry_clear(&entry); | |
2325 | error: | |
2326 | if (tlv) | |
2327 | wpabuf_free(tlv); | |
2328 | reply = wpas_dbus_error_invalid_args(message, NULL); | |
2329 | goto out; | |
2330 | } | |
2331 | ||
f94a85ee JM |
2332 | |
2333 | DBusMessage * wpas_dbus_handler_p2p_service_sd_res( | |
9abafccc JB |
2334 | DBusMessage *message, struct wpa_supplicant *wpa_s) |
2335 | { | |
2336 | DBusMessageIter iter_dict; | |
2337 | DBusMessage *reply = NULL; | |
2338 | DBusMessageIter iter; | |
2339 | struct wpa_dbus_dict_entry entry; | |
2340 | char *peer_object_path = NULL; | |
2341 | struct wpabuf *tlv = NULL; | |
2342 | int freq = 0; | |
2343 | int dlg_tok = 0; | |
2344 | u8 addr[ETH_ALEN]; | |
2345 | ||
2346 | dbus_message_iter_init(message, &iter); | |
2347 | ||
6aeeb6fa | 2348 | if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) |
9abafccc JB |
2349 | goto error; |
2350 | ||
2351 | while (wpa_dbus_dict_has_dict_entry(&iter_dict)) { | |
2352 | if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) | |
2353 | goto error; | |
2354 | ||
f94a85ee | 2355 | if (!os_strcmp(entry.key, "peer_object") && |
9abafccc JB |
2356 | entry.type == DBUS_TYPE_OBJECT_PATH) { |
2357 | peer_object_path = os_strdup(entry.str_value); | |
f94a85ee | 2358 | } else if (!os_strcmp(entry.key, "frequency") && |
9abafccc JB |
2359 | entry.type == DBUS_TYPE_INT32) { |
2360 | freq = entry.uint32_value; | |
f94a85ee | 2361 | } else if (!os_strcmp(entry.key, "dialog_token") && |
9abafccc JB |
2362 | entry.type == DBUS_TYPE_UINT32) { |
2363 | dlg_tok = entry.uint32_value; | |
f94a85ee | 2364 | } else if (!os_strcmp(entry.key, "tlvs")) { |
9abafccc JB |
2365 | if (entry.type != DBUS_TYPE_ARRAY || |
2366 | entry.array_type != DBUS_TYPE_BYTE) | |
2367 | goto error_clear; | |
2368 | tlv = wpabuf_alloc_copy(entry.bytearray_value, | |
2369 | entry.array_len); | |
2370 | } else | |
2371 | goto error_clear; | |
2372 | ||
2373 | wpa_dbus_dict_entry_clear(&entry); | |
2374 | } | |
2375 | if (!peer_object_path || | |
2376 | (parse_peer_object_path(peer_object_path, addr) < 0) || | |
b3bcc0f5 | 2377 | !p2p_peer_known(wpa_s->global->p2p, addr)) |
9abafccc JB |
2378 | goto error; |
2379 | ||
2380 | if (tlv == NULL) | |
2381 | goto error; | |
2382 | ||
2383 | wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv); | |
2384 | wpabuf_free(tlv); | |
2385 | out: | |
2386 | os_free(peer_object_path); | |
2387 | return reply; | |
2388 | error_clear: | |
2389 | wpa_dbus_dict_entry_clear(&entry); | |
2390 | error: | |
2391 | reply = wpas_dbus_error_invalid_args(message, NULL); | |
2392 | goto out; | |
2393 | } | |
2394 | ||
f94a85ee JM |
2395 | |
2396 | DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req( | |
2397 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2398 | { |
2399 | DBusMessageIter iter; | |
2400 | u64 req = 0; | |
2401 | ||
2402 | dbus_message_iter_init(message, &iter); | |
2403 | dbus_message_iter_get_basic(&iter, &req); | |
2404 | ||
2405 | if (req == 0) | |
2406 | goto error; | |
2407 | ||
7165c5dc | 2408 | if (!wpas_p2p_sd_cancel_request(wpa_s, req)) |
9abafccc JB |
2409 | goto error; |
2410 | ||
2411 | return NULL; | |
2412 | error: | |
2413 | return wpas_dbus_error_invalid_args(message, NULL); | |
2414 | } | |
2415 | ||
f94a85ee JM |
2416 | |
2417 | DBusMessage * wpas_dbus_handler_p2p_service_update( | |
2418 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2419 | { |
2420 | wpas_p2p_sd_service_update(wpa_s); | |
2421 | return NULL; | |
2422 | } | |
2423 | ||
f94a85ee JM |
2424 | |
2425 | DBusMessage * wpas_dbus_handler_p2p_serv_disc_external( | |
2426 | DBusMessage *message, struct wpa_supplicant *wpa_s) | |
9abafccc JB |
2427 | { |
2428 | DBusMessageIter iter; | |
2429 | int ext = 0; | |
2430 | ||
2431 | dbus_message_iter_init(message, &iter); | |
2432 | dbus_message_iter_get_basic(&iter, &ext); | |
2433 | ||
2434 | wpa_s->p2p_sd_over_ctrl_iface = ext; | |
2435 | ||
2436 | return NULL; | |
2437 | ||
2438 | } |