Add signal handling to supplicant test program
[framework/connectivity/connman.git] / tools / supplicant.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <string.h>
28 #include <syslog.h>
29
30 #include <glib.h>
31 #include <gdbus.h>
32
33 #include "supplicant.h"
34
35 #define DBG(fmt, arg...) do { \
36         syslog(LOG_DEBUG, "%s() " fmt, __FUNCTION__ , ## arg); \
37 } while (0)
38
39 #define SUPPLICANT_SERVICE      "fi.w1.wpa_supplicant1"
40 #define SUPPLICANT_INTERFACE    "fi.w1.wpa_supplicant1"
41 #define SUPPLICANT_PATH         "/fi/w1/wpa_supplicant1"
42
43 #define TIMEOUT 5000
44
45 static DBusConnection *connection;
46
47 static const struct supplicant_callbacks *callbacks_pointer;
48
49 static void show_property(const char *key, DBusMessageIter *iter)
50 {
51         DBusMessageIter array;
52         const char *str;
53         unsigned char byte;
54
55         switch (dbus_message_iter_get_arg_type(iter)) {
56         case DBUS_TYPE_STRING:
57         case DBUS_TYPE_OBJECT_PATH:
58                 dbus_message_iter_get_basic(iter, &str);
59                 DBG("%s = %s", key, str);
60                 break;
61         case DBUS_TYPE_BYTE:
62         case DBUS_TYPE_BOOLEAN:
63                 dbus_message_iter_get_basic(iter, &byte);
64                 DBG("%s = %u", key, byte);
65                 break;
66         case DBUS_TYPE_ARRAY:
67                 DBG("%s = {array}", key);
68                 dbus_message_iter_recurse(iter, &array);
69                 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
70                         dbus_message_iter_get_basic(&array, &str);
71                         DBG("  %s", str);
72                         dbus_message_iter_next(&array);
73                 }
74                 break;
75         default:
76                 DBG("%s = ...", key);
77                 break;
78         }
79 }
80
81 static void properties_decode(DBusMessageIter *iter)
82 {
83         DBusMessageIter dict;
84
85         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
86                 syslog(LOG_ERR, "Invalid message type");
87                 return;
88         }
89
90         dbus_message_iter_recurse(iter, &dict);
91
92         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
93                 DBusMessageIter entry, value;
94                 const char *key;
95
96                 dbus_message_iter_recurse(&dict, &entry);
97
98                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
99                         return;
100
101                 dbus_message_iter_get_basic(&entry, &key);
102                 dbus_message_iter_next(&entry);
103
104                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
105                         return;
106
107                 dbus_message_iter_recurse(&entry, &value);
108
109                 show_property(key, &value);
110
111                 dbus_message_iter_next(&dict);
112         }
113 }
114
115 static void properties_get_all_reply(DBusPendingCall *call, void *user_data)
116 {
117         DBusMessage *reply;
118         DBusMessageIter iter;
119
120         DBG("call %p", call);
121
122         reply = dbus_pending_call_steal_reply(call);
123         if (reply == NULL)
124                 return;
125
126         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
127                 goto failed;
128
129         if (dbus_message_iter_init(reply, &iter) == FALSE)
130                 goto failed;
131
132         DBG("success");
133
134         properties_decode(&iter);
135
136         dbus_message_unref(reply);
137
138         return;
139
140 failed:
141         dbus_message_unref(reply);
142 }
143
144 static int properties_get_all(const char *path, const char *interface)
145 {
146         DBusMessage *message;
147         DBusPendingCall *call;
148
149         DBG("");
150
151         message = dbus_message_new_method_call(SUPPLICANT_SERVICE, path,
152                                         DBUS_INTERFACE_PROPERTIES, "GetAll");
153         if (message == NULL)
154                 return -ENOMEM;
155
156         dbus_message_set_auto_start(message, FALSE);
157
158         dbus_message_append_args(message, DBUS_TYPE_STRING, &interface, NULL);
159
160         if (dbus_connection_send_with_reply(connection, message,
161                                                 &call, TIMEOUT) == FALSE) {
162                 syslog(LOG_ERR, "Failed to add interface");
163                 dbus_message_unref(message);
164                 return -EIO;
165         }
166
167         if (call == NULL) {
168                 syslog(LOG_ERR, "D-Bus connection not available");
169                 dbus_message_unref(message);
170                 return -EIO;
171         }
172
173         DBG("call %p", call);
174
175         dbus_pending_call_set_notify(call, properties_get_all_reply,
176                                                                 NULL, NULL);
177
178         dbus_message_unref(message);
179
180         return 0;
181 }
182
183 static DBusHandlerResult supplicant_filter(DBusConnection *conn,
184                                                 DBusMessage *msg, void *data)
185 {
186         int prefixlen = strlen(SUPPLICANT_INTERFACE);
187         const char *interface, *member, *path;
188
189         interface = dbus_message_get_interface(msg);
190         if (interface == NULL)
191                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
192
193         if (g_str_has_prefix(interface, SUPPLICANT_INTERFACE) == FALSE)
194                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
195
196         member = dbus_message_get_member(msg);
197         if (member == NULL)
198                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
199
200         path = dbus_message_get_path(msg);
201
202         syslog(LOG_DEBUG, "[ %s ]%s.%s", path, interface + prefixlen, member);
203
204         if (g_str_equal(member, "PropertiesChanged") == TRUE) {
205                 DBusMessageIter iter;
206
207                 if (dbus_message_iter_init(msg, &iter) == TRUE)
208                         properties_decode(&iter);
209         }
210
211         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
212 }
213
214 static const char *supplicant_rule1 = "type=signal,"
215                         "interface=" SUPPLICANT_INTERFACE;
216 static const char *supplicant_rule2 = "type=signal,"
217                         "interface=" SUPPLICANT_INTERFACE ".Interface";
218 static const char *supplicant_rule3 = "type=signal,"
219                         "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
220 static const char *supplicant_rule4 = "type=signal,"
221                         "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
222 static const char *supplicant_rule5 = "type=signal,"
223                         "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
224 static const char *supplicant_rule6 = "type=signal,"
225                         "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
226
227 int supplicant_register(const struct supplicant_callbacks *callbacks)
228 {
229         DBG("");
230
231         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
232         if (connection == NULL)
233                 return -EIO;
234
235         if (dbus_connection_add_filter(connection,
236                                 supplicant_filter, NULL, NULL) == FALSE) {
237                 dbus_connection_unref(connection);
238                 connection = NULL;
239                 return -EIO;
240         }
241
242         callbacks_pointer = callbacks;
243
244         dbus_bus_add_match(connection, supplicant_rule1, NULL);
245         dbus_bus_add_match(connection, supplicant_rule2, NULL);
246         dbus_bus_add_match(connection, supplicant_rule3, NULL);
247         dbus_bus_add_match(connection, supplicant_rule4, NULL);
248         dbus_bus_add_match(connection, supplicant_rule5, NULL);
249         dbus_bus_add_match(connection, supplicant_rule6, NULL);
250         dbus_connection_flush(connection);
251
252         properties_get_all(SUPPLICANT_PATH, SUPPLICANT_INTERFACE);
253
254         return 0;
255 }
256
257 void supplicant_unregister(const struct supplicant_callbacks *callbacks)
258 {
259         DBG("");
260
261         if (connection != NULL) {
262                 dbus_bus_remove_match(connection, supplicant_rule6, NULL);
263                 dbus_bus_remove_match(connection, supplicant_rule5, NULL);
264                 dbus_bus_remove_match(connection, supplicant_rule4, NULL);
265                 dbus_bus_remove_match(connection, supplicant_rule3, NULL);
266                 dbus_bus_remove_match(connection, supplicant_rule2, NULL);
267                 dbus_bus_remove_match(connection, supplicant_rule1, NULL);
268                 dbus_connection_flush(connection);
269
270                 dbus_connection_remove_filter(connection,
271                                                 supplicant_filter, NULL);
272
273                 dbus_connection_unref(connection);
274                 connection = NULL;
275         }
276
277         callbacks_pointer = NULL;
278 }