5 * Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 static DBusConnection *connection = NULL;
35 static guint agent_watch = 0;
36 static gchar *agent_path = NULL;
37 static gchar *agent_sender = NULL;
39 typedef void (*agent_queue_cb)(DBusMessage *reply, void *user_data);
42 struct connman_service *service;
44 DBusPendingCall *call;
46 agent_queue_cb callback;
50 static GList *agent_queue = NULL;
51 static struct agent_data *agent_request = NULL;
53 static void agent_free(void)
64 static void agent_disconnect(DBusConnection *conn, void *data)
71 int __connman_agent_register(const char *sender, const char *path)
73 DBG("sender %s path %s", sender, path);
75 if (agent_path != NULL)
78 agent_sender = g_strdup(sender);
79 agent_path = g_strdup(path);
81 agent_watch = g_dbus_add_disconnect_watch(connection, sender,
82 agent_disconnect, NULL, NULL);
87 int __connman_agent_unregister(const char *sender, const char *path)
89 DBG("sender %s path %s", sender, path);
91 if (agent_path == NULL)
95 g_dbus_remove_watch(connection, agent_watch);
102 static void agent_data_free(struct agent_data *data)
106 if (data->service != NULL)
107 connman_service_unref(data->service);
108 if (data->msg != NULL)
109 dbus_message_unref(data->msg);
110 if (data->call != NULL)
111 dbus_pending_call_cancel(data->call);
116 static void agent_receive_message(DBusPendingCall *call, void *user_data);
118 static int agent_send_next_request(void)
120 if (agent_request != NULL)
123 if (agent_queue == NULL)
126 agent_request = agent_queue->data;
127 agent_queue = g_list_remove(agent_queue, agent_request);
129 if (dbus_connection_send_with_reply(connection, agent_request->msg,
130 &agent_request->call,
131 agent_request->timeout)
135 if (agent_request->call == NULL)
138 if (dbus_pending_call_set_notify(agent_request->call,
139 agent_receive_message, agent_request,
143 dbus_message_unref(agent_request->msg);
144 agent_request->msg = NULL;
148 agent_data_free(agent_request);
149 agent_request = NULL;
153 static int agent_send_cancel(void)
155 DBusMessage *message;
157 if (agent_sender == NULL)
160 message = dbus_message_new_method_call(agent_sender, agent_path,
161 CONNMAN_AGENT_INTERFACE, "Cancel");
162 if (message != NULL) {
163 dbus_message_set_no_reply(message, TRUE);
164 g_dbus_send_message(connection, message);
168 connman_warn("Failed to send Cancel message to agent");
172 static void agent_receive_message(DBusPendingCall *call, void *user_data)
174 struct agent_data *queue_data = user_data;
177 DBG("waiting for %p received %p", agent_request, queue_data);
179 if (agent_request != queue_data) {
180 connman_error("Agent callback expected %p got %p",
181 agent_request, queue_data);
185 reply = dbus_pending_call_steal_reply(call);
186 dbus_pending_call_unref(call);
187 queue_data->call = NULL;
189 queue_data->callback(reply, queue_data->user_data);
190 dbus_message_unref(reply);
192 agent_data_free(queue_data);
193 agent_request = NULL;
195 agent_send_next_request();
198 static int agent_queue_message(struct connman_service *service,
199 DBusMessage *msg, int timeout,
200 agent_queue_cb callback, void *user_data)
202 struct agent_data *queue_data;
204 if (service == NULL || callback == NULL)
207 queue_data = g_new0(struct agent_data, 1);
208 if (queue_data == NULL)
211 queue_data->service = connman_service_ref(service);
212 queue_data->msg = dbus_message_ref(msg);
213 queue_data->timeout = timeout;
214 queue_data->callback = callback;
215 queue_data->user_data = user_data;
216 agent_queue = g_list_append(agent_queue, queue_data);
218 return agent_send_next_request();
221 void __connman_agent_cancel(struct connman_service *service)
224 struct agent_data *queued_req;
226 DBG("service %p", service);
230 while (item != NULL) {
231 next = g_list_next(item);
232 queued_req = item->data;
234 if (queued_req->service == service || service == NULL) {
235 agent_data_free(queued_req);
236 agent_queue = g_list_delete_link(agent_queue, item);
242 if (agent_request == NULL)
245 if (agent_request->service != service && service != NULL)
248 agent_data_free(agent_request);
249 agent_request = NULL;
253 agent_send_next_request();
256 static connman_bool_t check_reply_has_dict(DBusMessage *reply)
258 const char *signature = DBUS_TYPE_ARRAY_AS_STRING
259 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
260 DBUS_TYPE_STRING_AS_STRING
261 DBUS_TYPE_VARIANT_AS_STRING
262 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
264 if (dbus_message_has_signature(reply, signature) == TRUE)
267 connman_warn("Reply %s to %s from %s has wrong signature %s",
269 dbus_message_get_interface(reply),
270 dbus_message_get_sender(reply),
271 dbus_message_get_signature(reply));
276 struct request_input_reply {
277 struct connman_service *service;
278 authentication_cb_t callback;
282 static void request_input_passphrase_reply(DBusMessage *reply, void *user_data)
284 struct request_input_reply *passphrase_reply = user_data;
285 connman_bool_t values_received = FALSE;
286 connman_bool_t wps = FALSE;
287 const char *error = NULL;
288 char *identity = NULL;
289 char *passphrase = NULL;
294 DBusMessageIter iter, dict;
296 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
297 error = dbus_message_get_error_name(reply);
301 if (check_reply_has_dict(reply) == FALSE)
304 values_received = TRUE;
306 dbus_message_iter_init(reply, &iter);
307 dbus_message_iter_recurse(&iter, &dict);
308 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
309 DBusMessageIter entry, value;
311 dbus_message_iter_recurse(&dict, &entry);
312 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
315 dbus_message_iter_get_basic(&entry, &key);
317 if (g_str_equal(key, "Identity")) {
318 dbus_message_iter_next(&entry);
319 if (dbus_message_iter_get_arg_type(&entry)
320 != DBUS_TYPE_VARIANT)
322 dbus_message_iter_recurse(&entry, &value);
323 dbus_message_iter_get_basic(&value, &identity);
325 } else if (g_str_equal(key, "Passphrase")) {
326 dbus_message_iter_next(&entry);
327 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
329 dbus_message_iter_recurse(&entry, &value);
330 dbus_message_iter_get_basic(&value, &passphrase);
332 } else if (g_str_equal(key, "WPS")) {
335 dbus_message_iter_next(&entry);
336 if (dbus_message_iter_get_arg_type(&entry)
337 != DBUS_TYPE_VARIANT)
339 dbus_message_iter_recurse(&entry, &value);
340 dbus_message_iter_get_basic(&value, &wpspin);
342 } else if (g_str_equal(key, "Name")) {
343 dbus_message_iter_next(&entry);
344 if (dbus_message_iter_get_arg_type(&entry)
345 != DBUS_TYPE_VARIANT)
347 dbus_message_iter_recurse(&entry, &value);
348 dbus_message_iter_get_basic(&value, &name);
349 name_len = strlen(name);
350 } else if (g_str_equal(key, "SSID")) {
351 dbus_message_iter_next(&entry);
352 if (dbus_message_iter_get_arg_type(&entry)
353 != DBUS_TYPE_VARIANT)
355 dbus_message_iter_recurse(&entry, &value);
356 if (dbus_message_iter_get_arg_type(&value)
357 != DBUS_TYPE_VARIANT)
359 if (dbus_message_iter_get_element_type(&value)
360 != DBUS_TYPE_VARIANT)
362 dbus_message_iter_get_fixed_array(&value, &name,
365 dbus_message_iter_next(&dict);
369 passphrase_reply->callback(passphrase_reply->service, values_received,
371 identity, passphrase,
373 passphrase_reply->user_data);
374 connman_service_unref(passphrase_reply->service);
375 g_free(passphrase_reply);
378 static void request_input_append_alternates(DBusMessageIter *iter,
381 const char *str = user_data;
382 char **alternates, **alternative;
387 alternates = g_strsplit(str, ",", 0);
388 if (alternates == NULL)
391 for (alternative = alternates; *alternative != NULL; alternative++)
392 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
395 g_strfreev(alternates);
398 static void request_input_append_identity(DBusMessageIter *iter,
401 char *str = "string";
403 connman_dbus_dict_append_basic(iter, "Type",
404 DBUS_TYPE_STRING, &str);
406 connman_dbus_dict_append_basic(iter, "Requirement",
407 DBUS_TYPE_STRING, &str);
410 static void request_input_append_passphrase(DBusMessageIter *iter,
413 struct connman_service *service = user_data;
417 switch (__connman_service_get_security(service)) {
418 case CONNMAN_SERVICE_SECURITY_WEP:
421 case CONNMAN_SERVICE_SECURITY_PSK:
424 case CONNMAN_SERVICE_SECURITY_8021X:
425 phase2 = __connman_service_get_phase2(service);
427 if (phase2 != NULL && (
428 g_str_has_suffix(phase2, "GTC") == TRUE ||
429 g_str_has_suffix(phase2, "OTP") == TRUE))
432 value = "passphrase";
439 connman_dbus_dict_append_basic(iter, "Type",
440 DBUS_TYPE_STRING, &value);
442 connman_dbus_dict_append_basic(iter, "Requirement",
443 DBUS_TYPE_STRING, &value);
445 if (__connman_service_wps_enabled(service) == TRUE) {
446 connman_dbus_dict_append_array(iter, "Alternates",
448 request_input_append_alternates,
453 static void request_input_append_wps(DBusMessageIter *iter, void *user_data)
455 const char *str = "wpspin";
457 connman_dbus_dict_append_basic(iter, "Type",
458 DBUS_TYPE_STRING, &str);
460 connman_dbus_dict_append_basic(iter, "Requirement",
461 DBUS_TYPE_STRING, &str);
464 static void request_input_append_name(DBusMessageIter *iter, void *user_data)
466 const char *str = "string";
468 connman_dbus_dict_append_basic(iter, "Type",
469 DBUS_TYPE_STRING, &str);
471 connman_dbus_dict_append_basic(iter, "Requirement",
472 DBUS_TYPE_STRING, &str);
473 connman_dbus_dict_append_array(iter, "Alternates",
475 request_input_append_alternates,
479 static void request_input_append_ssid(DBusMessageIter *iter, void *user_data)
481 const char *str = "ssid";
483 connman_dbus_dict_append_basic(iter, "Type",
484 DBUS_TYPE_STRING, &str);
486 connman_dbus_dict_append_basic(iter, "Requirement",
487 DBUS_TYPE_STRING, &str);
490 static void request_input_append_password(DBusMessageIter *iter,
493 char *str = "passphrase";
495 connman_dbus_dict_append_basic(iter, "Type",
496 DBUS_TYPE_STRING, &str);
498 connman_dbus_dict_append_basic(iter, "Requirement",
499 DBUS_TYPE_STRING, &str);
502 struct previous_passphrase_data {
503 const char *passphrase;
507 static void request_input_append_previouspassphrase(DBusMessageIter *iter,
510 struct previous_passphrase_data *data = user_data;
511 const char *requirement = "informational";
513 connman_dbus_dict_append_basic(iter, "Type",
514 DBUS_TYPE_STRING, &data->type);
516 connman_dbus_dict_append_basic(iter, "Requirement",
517 DBUS_TYPE_STRING, &requirement);
519 connman_dbus_dict_append_basic(iter, "Value",
520 DBUS_TYPE_STRING, &data->passphrase);
523 static void previous_passphrase_handler(DBusMessageIter *iter,
524 struct connman_service *service)
526 enum connman_service_security security;
527 struct previous_passphrase_data data;
528 struct connman_network *network;
530 network = __connman_service_get_network(service);
531 data.passphrase = connman_network_get_string(network, "WiFi.PinWPS");
533 if (connman_network_get_bool(network, "WiFi.UseWPS") == TRUE &&
534 data.passphrase != NULL) {
535 data.type = "wpspin";
537 data.passphrase = __connman_service_get_passphrase(service);
538 if (data.passphrase == NULL)
541 security = __connman_service_get_security(service);
543 case CONNMAN_SERVICE_SECURITY_WEP:
546 case CONNMAN_SERVICE_SECURITY_PSK:
550 * This should never happen: no passphrase is set if security
551 * is not one of the above. */
557 connman_dbus_dict_append_dict(iter, "PreviousPassphrase",
558 request_input_append_previouspassphrase, &data);
561 static void request_input_login_reply(DBusMessage *reply, void *user_data)
563 struct request_input_reply *username_password_reply = user_data;
564 const char *error = NULL;
565 connman_bool_t values_received = FALSE;
566 char *username = NULL;
567 char *password = NULL;
569 DBusMessageIter iter, dict;
571 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
572 error = dbus_message_get_error_name(reply);
576 if (check_reply_has_dict(reply) == FALSE)
579 values_received = TRUE;
581 dbus_message_iter_init(reply, &iter);
582 dbus_message_iter_recurse(&iter, &dict);
583 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
584 DBusMessageIter entry, value;
586 dbus_message_iter_recurse(&dict, &entry);
587 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
590 dbus_message_iter_get_basic(&entry, &key);
592 if (g_str_equal(key, "Username")) {
593 dbus_message_iter_next(&entry);
594 if (dbus_message_iter_get_arg_type(&entry)
595 != DBUS_TYPE_VARIANT)
597 dbus_message_iter_recurse(&entry, &value);
598 dbus_message_iter_get_basic(&value, &username);
600 } else if (g_str_equal(key, "Password")) {
601 dbus_message_iter_next(&entry);
602 if (dbus_message_iter_get_arg_type(&entry) !=
605 dbus_message_iter_recurse(&entry, &value);
606 dbus_message_iter_get_basic(&value, &password);
609 dbus_message_iter_next(&dict);
613 username_password_reply->callback(username_password_reply->service,
614 values_received, NULL, 0,
617 username_password_reply->user_data);
618 connman_service_unref(username_password_reply->service);
619 g_free(username_password_reply);
622 int __connman_agent_request_passphrase_input(struct connman_service *service,
623 authentication_cb_t callback, void *user_data)
625 DBusMessage *message;
627 DBusMessageIter iter;
628 DBusMessageIter dict;
629 struct request_input_reply *passphrase_reply;
632 if (service == NULL || agent_path == NULL || callback == NULL)
635 message = dbus_message_new_method_call(agent_sender, agent_path,
636 CONNMAN_AGENT_INTERFACE,
641 dbus_message_iter_init_append(message, &iter);
643 path = __connman_service_get_path(service);
644 dbus_message_iter_append_basic(&iter,
645 DBUS_TYPE_OBJECT_PATH, &path);
647 connman_dbus_dict_open(&iter, &dict);
649 if (__connman_service_is_hidden(service)) {
650 connman_dbus_dict_append_dict(&dict, "Name",
651 request_input_append_name, NULL);
652 connman_dbus_dict_append_dict(&dict, "SSID",
653 request_input_append_ssid, NULL);
656 if (__connman_service_get_security(service) ==
657 CONNMAN_SERVICE_SECURITY_8021X) {
658 connman_dbus_dict_append_dict(&dict, "Identity",
659 request_input_append_identity, service);
662 if (__connman_service_get_security(service) !=
663 CONNMAN_SERVICE_SECURITY_NONE) {
664 connman_dbus_dict_append_dict(&dict, "Passphrase",
665 request_input_append_passphrase, service);
667 previous_passphrase_handler(&dict, service);
670 if (__connman_service_wps_enabled(service) == TRUE) {
671 connman_dbus_dict_append_dict(&dict, "WPS",
672 request_input_append_wps, NULL);
675 connman_dbus_dict_close(&iter, &dict);
677 passphrase_reply = g_try_new0(struct request_input_reply, 1);
678 if (passphrase_reply == NULL) {
679 dbus_message_unref(message);
683 passphrase_reply->service = connman_service_ref(service);
684 passphrase_reply->callback = callback;
685 passphrase_reply->user_data = user_data;
687 err = agent_queue_message(service, message,
688 connman_timeout_input_request(),
689 request_input_passphrase_reply,
692 if (err < 0 && err != -EBUSY) {
693 DBG("error %d sending agent message", err);
694 connman_service_unref(service);
695 dbus_message_unref(message);
696 g_free(passphrase_reply);
700 dbus_message_unref(message);
705 int __connman_agent_request_login_input(struct connman_service *service,
706 authentication_cb_t callback, void *user_data)
708 DBusMessage *message;
710 DBusMessageIter iter;
711 DBusMessageIter dict;
712 struct request_input_reply *username_password_reply;
715 if (service == NULL || agent_path == NULL || callback == NULL)
718 message = dbus_message_new_method_call(agent_sender, agent_path,
719 CONNMAN_AGENT_INTERFACE,
724 dbus_message_iter_init_append(message, &iter);
726 path = __connman_service_get_path(service);
727 dbus_message_iter_append_basic(&iter,
728 DBUS_TYPE_OBJECT_PATH, &path);
730 connman_dbus_dict_open(&iter, &dict);
732 connman_dbus_dict_append_dict(&dict, "Username",
733 request_input_append_identity, service);
735 connman_dbus_dict_append_dict(&dict, "Password",
736 request_input_append_password, service);
738 connman_dbus_dict_close(&iter, &dict);
740 username_password_reply = g_try_new0(struct request_input_reply, 1);
741 if (username_password_reply == NULL) {
742 dbus_message_unref(message);
746 username_password_reply->service = connman_service_ref(service);
747 username_password_reply->callback = callback;
748 username_password_reply->user_data = user_data;
750 err = agent_queue_message(service, message,
751 connman_timeout_input_request(),
752 request_input_login_reply, username_password_reply);
753 if (err < 0 && err != -EBUSY) {
754 DBG("error %d sending agent request", err);
755 connman_service_unref(service);
756 dbus_message_unref(message);
757 g_free(username_password_reply);
761 dbus_message_unref(message);
766 struct request_browser_reply_data {
767 struct connman_service *service;
768 browser_authentication_cb_t callback;
772 static void request_browser_reply(DBusMessage *reply, void *user_data)
774 struct request_browser_reply_data *browser_reply_data = user_data;
775 connman_bool_t result = FALSE;
776 const char *error = NULL;
778 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
779 error = dbus_message_get_error_name(reply);
786 browser_reply_data->callback(browser_reply_data->service, result,
787 error, browser_reply_data->user_data);
788 connman_service_unref(browser_reply_data->service);
789 g_free(browser_reply_data);
792 int __connman_agent_request_browser(struct connman_service *service,
793 browser_authentication_cb_t callback,
794 const char *url, void *user_data)
796 struct request_browser_reply_data *browser_reply_data;
797 DBusMessage *message;
798 DBusMessageIter iter;
802 if (service == NULL || agent_path == NULL || callback == NULL)
808 message = dbus_message_new_method_call(agent_sender, agent_path,
809 CONNMAN_AGENT_INTERFACE,
814 dbus_message_iter_init_append(message, &iter);
816 path = __connman_service_get_path(service);
817 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
819 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &url);
821 browser_reply_data = g_try_new0(struct request_browser_reply_data, 1);
822 if (browser_reply_data == NULL) {
823 dbus_message_unref(message);
827 browser_reply_data->service = connman_service_ref(service);
828 browser_reply_data->callback = callback;
829 browser_reply_data->user_data = user_data;
831 err = agent_queue_message(service, message,
832 connman_timeout_browser_launch(),
833 request_browser_reply, browser_reply_data);
835 if (err < 0 && err != -EBUSY) {
836 DBG("error %d sending browser request", err);
837 connman_service_unref(service);
838 dbus_message_unref(message);
839 g_free(browser_reply_data);
843 dbus_message_unref(message);
848 struct report_error_data {
849 struct connman_service *service;
850 report_error_cb_t callback;
854 static void report_error_reply(DBusMessage *reply, void *user_data)
856 struct report_error_data *report_error = user_data;
857 gboolean retry = FALSE;
858 const char *dbus_err;
860 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
861 dbus_err = dbus_message_get_error_name(reply);
862 if (dbus_err != NULL &&
864 CONNMAN_AGENT_INTERFACE ".Error.Retry") == 0)
868 report_error->callback(report_error->service, retry,
869 report_error->user_data);
870 connman_service_unref(report_error->service);
871 g_free(report_error);
874 int __connman_agent_report_error(struct connman_service *service,
876 report_error_cb_t callback, void *user_data)
878 DBusMessage *message;
879 DBusMessageIter iter;
881 struct report_error_data *report_error;
884 if (service == NULL || agent_path == NULL || error == NULL ||
888 message = dbus_message_new_method_call(agent_sender, agent_path,
889 CONNMAN_AGENT_INTERFACE,
894 dbus_message_iter_init_append(message, &iter);
896 path = __connman_service_get_path(service);
897 dbus_message_iter_append_basic(&iter,
898 DBUS_TYPE_OBJECT_PATH, &path);
899 dbus_message_iter_append_basic(&iter,
900 DBUS_TYPE_STRING, &error);
902 report_error = g_try_new0(struct report_error_data, 1);
903 if (report_error == NULL) {
904 dbus_message_unref(message);
908 report_error->service = connman_service_ref(service);
909 report_error->callback = callback;
910 report_error->user_data = user_data;
912 err = agent_queue_message(service, message,
913 connman_timeout_input_request(),
914 report_error_reply, report_error);
915 if (err < 0 && err != -EBUSY) {
916 DBG("error %d sending error request", err);
917 connman_service_unref(service);
918 g_free(report_error);
919 dbus_message_unref(message);
923 dbus_message_unref(message);
928 int __connman_agent_init(void)
932 connection = connman_dbus_get_connection();
933 if (connection == NULL)
939 void __connman_agent_cleanup(void)
941 DBusMessage *message;
945 if (connection == NULL)
949 g_dbus_remove_watch(connection, agent_watch);
951 if (agent_path == NULL)
954 message = dbus_message_new_method_call(agent_sender, agent_path,
955 CONNMAN_AGENT_INTERFACE, "Release");
959 dbus_message_set_no_reply(message, TRUE);
961 g_dbus_send_message(connection, message);
965 dbus_connection_unref(connection);