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 void agent_receive_message(DBusPendingCall *call, void *user_data)
155 struct agent_data *queue_data = user_data;
158 DBG("waiting for %p received %p", agent_request, queue_data);
160 if (agent_request != queue_data) {
161 connman_error("Agent callback expected %p got %p",
162 agent_request, queue_data);
166 reply = dbus_pending_call_steal_reply(call);
167 dbus_pending_call_unref(call);
168 queue_data->call = NULL;
170 queue_data->callback(reply, queue_data->user_data);
171 dbus_message_unref(reply);
173 agent_data_free(queue_data);
174 agent_request = NULL;
176 agent_send_next_request();
179 static int agent_queue_message(struct connman_service *service,
180 DBusMessage *msg, int timeout,
181 agent_queue_cb callback, void *user_data)
183 struct agent_data *queue_data;
185 if (service == NULL || callback == NULL)
188 queue_data = g_new0(struct agent_data, 1);
189 if (queue_data == NULL)
192 queue_data->service = connman_service_ref(service);
193 queue_data->msg = dbus_message_ref(msg);
194 queue_data->timeout = timeout;
195 queue_data->callback = callback;
196 queue_data->user_data = user_data;
197 agent_queue = g_list_append(agent_queue, queue_data);
199 return agent_send_next_request();
202 static connman_bool_t check_reply_has_dict(DBusMessage *reply)
204 const char *signature = DBUS_TYPE_ARRAY_AS_STRING
205 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
206 DBUS_TYPE_STRING_AS_STRING
207 DBUS_TYPE_VARIANT_AS_STRING
208 DBUS_DICT_ENTRY_END_CHAR_AS_STRING;
210 if (dbus_message_has_signature(reply, signature) == TRUE)
213 connman_warn("Reply %s to %s from %s has wrong signature %s",
215 dbus_message_get_interface(reply),
216 dbus_message_get_sender(reply),
217 dbus_message_get_signature(reply));
222 struct request_input_reply {
223 struct connman_service *service;
224 authentication_cb_t callback;
228 static void request_input_passphrase_reply(DBusMessage *reply, void *user_data)
230 struct request_input_reply *passphrase_reply = user_data;
231 connman_bool_t values_received = FALSE;
232 connman_bool_t wps = FALSE;
233 const char *error = NULL;
234 char *identity = NULL;
235 char *passphrase = NULL;
240 DBusMessageIter iter, dict;
242 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
243 error = dbus_message_get_error_name(reply);
247 if (check_reply_has_dict(reply) == FALSE)
250 values_received = TRUE;
252 dbus_message_iter_init(reply, &iter);
253 dbus_message_iter_recurse(&iter, &dict);
254 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
255 DBusMessageIter entry, value;
257 dbus_message_iter_recurse(&dict, &entry);
258 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
261 dbus_message_iter_get_basic(&entry, &key);
263 if (g_str_equal(key, "Identity")) {
264 dbus_message_iter_next(&entry);
265 if (dbus_message_iter_get_arg_type(&entry)
266 != DBUS_TYPE_VARIANT)
268 dbus_message_iter_recurse(&entry, &value);
269 dbus_message_iter_get_basic(&value, &identity);
271 } else if (g_str_equal(key, "Passphrase")) {
272 dbus_message_iter_next(&entry);
273 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
275 dbus_message_iter_recurse(&entry, &value);
276 dbus_message_iter_get_basic(&value, &passphrase);
278 } else if (g_str_equal(key, "WPS")) {
281 dbus_message_iter_next(&entry);
282 if (dbus_message_iter_get_arg_type(&entry)
283 != DBUS_TYPE_VARIANT)
285 dbus_message_iter_recurse(&entry, &value);
286 dbus_message_iter_get_basic(&value, &wpspin);
288 } else if (g_str_equal(key, "Name")) {
289 dbus_message_iter_next(&entry);
290 if (dbus_message_iter_get_arg_type(&entry)
291 != DBUS_TYPE_VARIANT)
293 dbus_message_iter_recurse(&entry, &value);
294 dbus_message_iter_get_basic(&value, &name);
295 name_len = strlen(name);
296 } else if (g_str_equal(key, "SSID")) {
297 dbus_message_iter_next(&entry);
298 if (dbus_message_iter_get_arg_type(&entry)
299 != DBUS_TYPE_VARIANT)
301 dbus_message_iter_recurse(&entry, &value);
302 if (dbus_message_iter_get_arg_type(&value)
303 != DBUS_TYPE_VARIANT)
305 if (dbus_message_iter_get_element_type(&value)
306 != DBUS_TYPE_VARIANT)
308 dbus_message_iter_get_fixed_array(&value, &name,
311 dbus_message_iter_next(&dict);
315 passphrase_reply->callback(passphrase_reply->service, values_received,
317 identity, passphrase,
319 passphrase_reply->user_data);
320 connman_service_unref(passphrase_reply->service);
321 g_free(passphrase_reply);
324 static void request_input_append_alternates(DBusMessageIter *iter,
327 const char *str = user_data;
328 char **alternates, **alternative;
333 alternates = g_strsplit(str, ",", 0);
334 if (alternates == NULL)
337 for (alternative = alternates; *alternative != NULL; alternative++)
338 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
341 g_strfreev(alternates);
344 static void request_input_append_identity(DBusMessageIter *iter,
347 char *str = "string";
349 connman_dbus_dict_append_basic(iter, "Type",
350 DBUS_TYPE_STRING, &str);
352 connman_dbus_dict_append_basic(iter, "Requirement",
353 DBUS_TYPE_STRING, &str);
356 static void request_input_append_passphrase(DBusMessageIter *iter,
359 struct connman_service *service = user_data;
363 switch (__connman_service_get_security(service)) {
364 case CONNMAN_SERVICE_SECURITY_WEP:
367 case CONNMAN_SERVICE_SECURITY_PSK:
370 case CONNMAN_SERVICE_SECURITY_8021X:
371 phase2 = __connman_service_get_phase2(service);
373 if (phase2 != NULL && (
374 g_str_has_suffix(phase2, "GTC") == TRUE ||
375 g_str_has_suffix(phase2, "OTP") == TRUE))
378 value = "passphrase";
385 connman_dbus_dict_append_basic(iter, "Type",
386 DBUS_TYPE_STRING, &value);
388 connman_dbus_dict_append_basic(iter, "Requirement",
389 DBUS_TYPE_STRING, &value);
391 if (__connman_service_wps_enabled(service) == TRUE) {
392 connman_dbus_dict_append_array(iter, "Alternates",
394 request_input_append_alternates,
399 static void request_input_append_wps(DBusMessageIter *iter, void *user_data)
401 const char *str = "wpspin";
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_name(DBusMessageIter *iter, void *user_data)
412 const char *str = "string";
414 connman_dbus_dict_append_basic(iter, "Type",
415 DBUS_TYPE_STRING, &str);
417 connman_dbus_dict_append_basic(iter, "Requirement",
418 DBUS_TYPE_STRING, &str);
419 connman_dbus_dict_append_array(iter, "Alternates",
421 request_input_append_alternates,
425 static void request_input_append_ssid(DBusMessageIter *iter, void *user_data)
427 const char *str = "ssid";
429 connman_dbus_dict_append_basic(iter, "Type",
430 DBUS_TYPE_STRING, &str);
432 connman_dbus_dict_append_basic(iter, "Requirement",
433 DBUS_TYPE_STRING, &str);
436 static void request_input_append_password(DBusMessageIter *iter,
439 char *str = "passphrase";
441 connman_dbus_dict_append_basic(iter, "Type",
442 DBUS_TYPE_STRING, &str);
444 connman_dbus_dict_append_basic(iter, "Requirement",
445 DBUS_TYPE_STRING, &str);
448 struct previous_passphrase_data {
449 const char *passphrase;
453 static void request_input_append_previouspassphrase(DBusMessageIter *iter,
456 struct previous_passphrase_data *data = user_data;
457 const char *requirement = "informational";
459 connman_dbus_dict_append_basic(iter, "Type",
460 DBUS_TYPE_STRING, &data->type);
462 connman_dbus_dict_append_basic(iter, "Requirement",
463 DBUS_TYPE_STRING, &requirement);
465 connman_dbus_dict_append_basic(iter, "Value",
466 DBUS_TYPE_STRING, &data->passphrase);
469 static void previous_passphrase_handler(DBusMessageIter *iter,
470 struct connman_service *service)
472 enum connman_service_security security;
473 struct previous_passphrase_data data;
474 struct connman_network *network;
476 network = __connman_service_get_network(service);
477 data.passphrase = connman_network_get_string(network, "WiFi.PinWPS");
479 if (connman_network_get_bool(network, "WiFi.UseWPS") == TRUE &&
480 data.passphrase != NULL) {
481 data.type = "wpspin";
483 data.passphrase = __connman_service_get_passphrase(service);
484 if (data.passphrase == NULL)
487 security = __connman_service_get_security(service);
489 case CONNMAN_SERVICE_SECURITY_WEP:
492 case CONNMAN_SERVICE_SECURITY_PSK:
496 * This should never happen: no passphrase is set if security
497 * is not one of the above. */
503 connman_dbus_dict_append_dict(iter, "PreviousPassphrase",
504 request_input_append_previouspassphrase, &data);
507 static void request_input_login_reply(DBusMessage *reply, void *user_data)
509 struct request_input_reply *username_password_reply = user_data;
510 const char *error = NULL;
511 connman_bool_t values_received = FALSE;
512 char *username = NULL;
513 char *password = NULL;
515 DBusMessageIter iter, dict;
517 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
518 error = dbus_message_get_error_name(reply);
522 if (check_reply_has_dict(reply) == FALSE)
525 values_received = TRUE;
527 dbus_message_iter_init(reply, &iter);
528 dbus_message_iter_recurse(&iter, &dict);
529 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
530 DBusMessageIter entry, value;
532 dbus_message_iter_recurse(&dict, &entry);
533 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
536 dbus_message_iter_get_basic(&entry, &key);
538 if (g_str_equal(key, "Username")) {
539 dbus_message_iter_next(&entry);
540 if (dbus_message_iter_get_arg_type(&entry)
541 != DBUS_TYPE_VARIANT)
543 dbus_message_iter_recurse(&entry, &value);
544 dbus_message_iter_get_basic(&value, &username);
546 } else if (g_str_equal(key, "Password")) {
547 dbus_message_iter_next(&entry);
548 if (dbus_message_iter_get_arg_type(&entry) !=
551 dbus_message_iter_recurse(&entry, &value);
552 dbus_message_iter_get_basic(&value, &password);
555 dbus_message_iter_next(&dict);
559 username_password_reply->callback(username_password_reply->service,
560 values_received, NULL, 0,
563 username_password_reply->user_data);
564 connman_service_unref(username_password_reply->service);
565 g_free(username_password_reply);
568 int __connman_agent_request_passphrase_input(struct connman_service *service,
569 authentication_cb_t callback, void *user_data)
571 DBusMessage *message;
573 DBusMessageIter iter;
574 DBusMessageIter dict;
575 struct request_input_reply *passphrase_reply;
578 if (service == NULL || agent_path == NULL || callback == NULL)
581 message = dbus_message_new_method_call(agent_sender, agent_path,
582 CONNMAN_AGENT_INTERFACE,
587 dbus_message_iter_init_append(message, &iter);
589 path = __connman_service_get_path(service);
590 dbus_message_iter_append_basic(&iter,
591 DBUS_TYPE_OBJECT_PATH, &path);
593 connman_dbus_dict_open(&iter, &dict);
595 if (__connman_service_is_hidden(service)) {
596 connman_dbus_dict_append_dict(&dict, "Name",
597 request_input_append_name, NULL);
598 connman_dbus_dict_append_dict(&dict, "SSID",
599 request_input_append_ssid, NULL);
602 if (__connman_service_get_security(service) ==
603 CONNMAN_SERVICE_SECURITY_8021X) {
604 connman_dbus_dict_append_dict(&dict, "Identity",
605 request_input_append_identity, service);
608 if (__connman_service_get_security(service) !=
609 CONNMAN_SERVICE_SECURITY_NONE) {
610 connman_dbus_dict_append_dict(&dict, "Passphrase",
611 request_input_append_passphrase, service);
613 previous_passphrase_handler(&dict, service);
616 if (__connman_service_wps_enabled(service) == TRUE) {
617 connman_dbus_dict_append_dict(&dict, "WPS",
618 request_input_append_wps, NULL);
621 connman_dbus_dict_close(&iter, &dict);
623 passphrase_reply = g_try_new0(struct request_input_reply, 1);
624 if (passphrase_reply == NULL) {
625 dbus_message_unref(message);
629 passphrase_reply->service = connman_service_ref(service);
630 passphrase_reply->callback = callback;
631 passphrase_reply->user_data = user_data;
633 err = agent_queue_message(service, message,
634 connman_timeout_input_request(),
635 request_input_passphrase_reply,
638 if (err < 0 && err != -EBUSY) {
639 DBG("error %d sending agent message", err);
640 connman_service_unref(service);
641 dbus_message_unref(message);
642 g_free(passphrase_reply);
646 dbus_message_unref(message);
651 int __connman_agent_request_login_input(struct connman_service *service,
652 authentication_cb_t callback, void *user_data)
654 DBusMessage *message;
656 DBusMessageIter iter;
657 DBusMessageIter dict;
658 struct request_input_reply *username_password_reply;
661 if (service == NULL || agent_path == NULL || callback == NULL)
664 message = dbus_message_new_method_call(agent_sender, agent_path,
665 CONNMAN_AGENT_INTERFACE,
670 dbus_message_iter_init_append(message, &iter);
672 path = __connman_service_get_path(service);
673 dbus_message_iter_append_basic(&iter,
674 DBUS_TYPE_OBJECT_PATH, &path);
676 connman_dbus_dict_open(&iter, &dict);
678 connman_dbus_dict_append_dict(&dict, "Username",
679 request_input_append_identity, service);
681 connman_dbus_dict_append_dict(&dict, "Password",
682 request_input_append_password, service);
684 connman_dbus_dict_close(&iter, &dict);
686 username_password_reply = g_try_new0(struct request_input_reply, 1);
687 if (username_password_reply == NULL) {
688 dbus_message_unref(message);
692 username_password_reply->service = connman_service_ref(service);
693 username_password_reply->callback = callback;
694 username_password_reply->user_data = user_data;
696 err = agent_queue_message(service, message,
697 connman_timeout_input_request(),
698 request_input_login_reply, username_password_reply);
699 if (err < 0 && err != -EBUSY) {
700 DBG("error %d sending agent request", err);
701 connman_service_unref(service);
702 dbus_message_unref(message);
703 g_free(username_password_reply);
707 dbus_message_unref(message);
712 struct request_browser_reply_data {
713 struct connman_service *service;
714 browser_authentication_cb_t callback;
718 static void request_browser_reply(DBusMessage *reply, void *user_data)
720 struct request_browser_reply_data *browser_reply_data = user_data;
721 connman_bool_t result = FALSE;
722 const char *error = NULL;
724 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
725 error = dbus_message_get_error_name(reply);
732 browser_reply_data->callback(browser_reply_data->service, result,
733 error, browser_reply_data->user_data);
734 connman_service_unref(browser_reply_data->service);
735 g_free(browser_reply_data);
738 int __connman_agent_request_browser(struct connman_service *service,
739 browser_authentication_cb_t callback,
740 const char *url, void *user_data)
742 struct request_browser_reply_data *browser_reply_data;
743 DBusMessage *message;
744 DBusMessageIter iter;
748 if (service == NULL || agent_path == NULL || callback == NULL)
754 message = dbus_message_new_method_call(agent_sender, agent_path,
755 CONNMAN_AGENT_INTERFACE,
760 dbus_message_iter_init_append(message, &iter);
762 path = __connman_service_get_path(service);
763 dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
765 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &url);
767 browser_reply_data = g_try_new0(struct request_browser_reply_data, 1);
768 if (browser_reply_data == NULL) {
769 dbus_message_unref(message);
773 browser_reply_data->service = connman_service_ref(service);
774 browser_reply_data->callback = callback;
775 browser_reply_data->user_data = user_data;
777 err = agent_queue_message(service, message,
778 connman_timeout_browser_launch(),
779 request_browser_reply, browser_reply_data);
781 if (err < 0 && err != -EBUSY) {
782 DBG("error %d sending browser request", err);
783 connman_service_unref(service);
784 dbus_message_unref(message);
785 g_free(browser_reply_data);
789 dbus_message_unref(message);
794 struct report_error_data {
795 struct connman_service *service;
796 report_error_cb_t callback;
800 static void report_error_reply(DBusMessage *reply, void *user_data)
802 struct report_error_data *report_error = user_data;
803 gboolean retry = FALSE;
804 const char *dbus_err;
806 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
807 dbus_err = dbus_message_get_error_name(reply);
808 if (dbus_err != NULL &&
810 CONNMAN_AGENT_INTERFACE ".Error.Retry") == 0)
814 report_error->callback(report_error->service, retry,
815 report_error->user_data);
816 connman_service_unref(report_error->service);
817 g_free(report_error);
820 int __connman_agent_report_error(struct connman_service *service,
822 report_error_cb_t callback, void *user_data)
824 DBusMessage *message;
825 DBusMessageIter iter;
827 struct report_error_data *report_error;
830 if (service == NULL || agent_path == NULL || error == NULL ||
834 message = dbus_message_new_method_call(agent_sender, agent_path,
835 CONNMAN_AGENT_INTERFACE,
840 dbus_message_iter_init_append(message, &iter);
842 path = __connman_service_get_path(service);
843 dbus_message_iter_append_basic(&iter,
844 DBUS_TYPE_OBJECT_PATH, &path);
845 dbus_message_iter_append_basic(&iter,
846 DBUS_TYPE_STRING, &error);
848 report_error = g_try_new0(struct report_error_data, 1);
849 if (report_error == NULL) {
850 dbus_message_unref(message);
854 report_error->service = connman_service_ref(service);
855 report_error->callback = callback;
856 report_error->user_data = user_data;
858 err = agent_queue_message(service, message,
859 connman_timeout_input_request(),
860 report_error_reply, report_error);
861 if (err < 0 && err != -EBUSY) {
862 DBG("error %d sending error request", err);
863 connman_service_unref(service);
864 g_free(report_error);
865 dbus_message_unref(message);
869 dbus_message_unref(message);
874 int __connman_agent_init(void)
878 connection = connman_dbus_get_connection();
879 if (connection == NULL)
885 void __connman_agent_cleanup(void)
887 DBusMessage *message;
891 if (connection == NULL)
895 g_dbus_remove_watch(connection, agent_watch);
897 if (agent_path == NULL)
900 message = dbus_message_new_method_call(agent_sender, agent_path,
901 CONNMAN_AGENT_INTERFACE, "Release");
905 dbus_message_set_no_reply(message, TRUE);
907 g_dbus_send_message(connection, message);
911 dbus_connection_unref(connection);