initial web page
[libicd-wpa] / wlan.c
1 /**
2   @file wlan.c
3
4   Copyright (C) 2004 Nokia Corporation. All rights reserved.
5   
6   Copyright (C) 2009 Javier S. Pedro
7
8   @author Janne Ylalehto <janne.ylalehto@nokia.com>
9   @author Johan Hedberg <johan.hedberg@nokia.com> 
10   
11   @author Javier S. Pedro <javispedro@javispedro.com>
12
13   This file is part of libicd-network-wpa.
14
15   This program is free software; you can redistribute it and/or modify it
16   under the terms of the GNU General Public License as published by the
17   Free Software Foundation; either version 2 of the License, or (at your
18   option) any later version.
19
20   This program is distributed in the hope that it will be useful, but
21   WITHOUT ANY WARRANTY; without even the implied warranty of
22   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23   General Public License for more details.
24
25   You should have received a copy of the GNU General Public License along
26   with this program; if not, write to the Free Software Foundation, Inc.,
27   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
28
29 */
30
31 #include <string.h>
32
33 #include <glib.h>
34 #include <dbus/dbus.h>
35
36 #include <wlancond.h>
37 #include <wlancond-dbus.h>
38 #include <wlancond-supp.h>
39
40 #include "common.h"
41 #include "dbus.h"
42 #include "dbus-helper.h"
43 #include "wlan.h"
44 #include "log.h"
45  
46 /* -- SCANNING -- */
47
48 static wlan_found_ap found_ap_cb = NULL;
49
50 int wlan_scan(const char * ssid, wlan_found_ap new_found_ap_cb)
51 {
52         DBusMessage *msg, *reply;
53         DBusError error;
54         
55         DLOG_DEBUG("%s: %s (active)", __func__, ssid);
56         
57         dbus_error_init(&error);
58         
59         found_ap_cb = new_found_ap_cb;
60         
61         msg = new_dbus_method_call(
62                 WLANCOND_SERVICE,
63                 WLANCOND_REQ_PATH,
64                 WLANCOND_REQ_INTERFACE,
65                 WLANCOND_SCAN_REQ);
66         
67         gint32 power_level = WLANCOND_TX_POWER100;
68         guint32 flags = 0;
69         
70         append_dbus_args(
71                 msg,
72                 DBUS_TYPE_INT32, &power_level,
73                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, strlen(ssid) + 1,
74                 DBUS_TYPE_UINT32, &flags,
75                 
76                 DBUS_TYPE_INVALID);
77
78         reply = dbus_connection_send_with_reply_and_block(get_dbus_connection(),
79                         msg, -1, &error);
80         
81         dbus_message_unref(msg);
82                 
83         if (reply) {
84                 DLOG_DEBUG("Scan reply OK");
85                 dbus_message_unref(reply);
86                 
87                 return 0;
88         } else if (dbus_error_is_set(&error)) {
89                 DLOG_INFO("Scan pending call result:%s", error.name);
90                 dbus_error_free(&error);
91                 found_ap_cb = NULL;
92                 return -1;
93         } else {
94                 DLOG_WARN("Scan without reply");
95                 found_ap_cb = NULL;
96                 return -1;
97         } 
98 }
99
100 gboolean wlan_is_scanning()
101 {       
102         return found_ap_cb ? TRUE : FALSE;
103 }
104
105 void wlan_notify_ap(const char *ssid, const char *bssid,
106         int rssi, unsigned int channel, unsigned int cap_bits)
107 {       
108         if (found_ap_cb)
109                 found_ap_cb(SEARCH_CONTINUE, ssid, bssid, rssi / 2 - 110);
110 }
111
112 void wlan_notify_end_of_search()
113 {       
114         wlan_found_ap prev_found_ap_cb = found_ap_cb;
115         found_ap_cb = NULL;
116         
117         // A new search may be started right after calling this callback
118         
119         if (prev_found_ap_cb)
120                 prev_found_ap_cb(SEARCH_FINISHED, NULL, NULL, 0);
121 }
122
123 /* - CONNECTING - */
124
125 static wlan_connected connected_cb;
126
127 static void connect_reply_cb(DBusPendingCall *pending, void *user_data)
128 {
129         DBusMessage *reply;
130         DBusError error;
131
132         DLOG_DEBUG("Connect reply callback");
133         
134         dbus_error_init(&error);
135         
136         reply = dbus_pending_call_steal_reply(pending);
137         
138         if (dbus_set_error_from_message(&error, reply)) {
139                 
140                 DLOG_DEBUG("Connect pending call result:%s", error.name);
141                 
142                 connected_cb(-1, error.name);
143                 dbus_error_free(&error);
144         } else if (reply) {
145                 connected_cb(0, NULL);
146         }
147         
148         if (reply) 
149                 dbus_message_unref(reply);
150         dbus_pending_call_unref(pending);
151 }
152
153 void wlan_connect(const char * ssid, wlan_connected _connected_cb)
154 {
155         DBusMessage *msg;
156         DBusPendingCall *pending;
157         
158         DLOG_DEBUG("%s: %s", __func__, ssid);
159         
160         connected_cb = _connected_cb;
161         
162         msg = new_dbus_method_call(
163                 WLANCOND_SERVICE,
164                 WLANCOND_REQ_PATH,
165                 WLANCOND_REQ_INTERFACE,
166                 WLANCOND_SETTINGS_AND_CONNECT_REQ);
167         
168         guint32 dummy = 0;
169         guint32 *dummyP = &dummy;
170         
171         gint32 power_level, mode, encryption, default_key;
172         guint32 adhoc_channel, flags;
173         
174         power_level = WLANCOND_TX_POWER100;
175         mode = WLANCOND_INFRA;
176         encryption = 0;
177         default_key = 0;
178         adhoc_channel = 0;
179         flags = WLANCOND_USE_SUPPLICANT;
180         
181         append_dbus_args(
182                 msg,
183                 DBUS_TYPE_INT32, &power_level,
184                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, strlen(ssid),
185                 DBUS_TYPE_INT32, &mode,
186                 DBUS_TYPE_INT32, &encryption,
187                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
188                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
189                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
190                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
191                 DBUS_TYPE_INT32, &default_key,
192                 DBUS_TYPE_UINT32, &adhoc_channel,
193                 DBUS_TYPE_UINT32, &flags,               
194                 DBUS_TYPE_INVALID);
195
196         if (!dbus_connection_send_with_reply(get_dbus_connection(), 
197                                              msg, &pending, -1))
198                 die("Out of memory");
199         
200         if (!dbus_pending_call_set_notify(pending, connect_reply_cb, NULL, NULL))
201                 die("Out of memory");
202         
203         dbus_message_unref(msg);
204 }
205
206 static void disconnect_reply_cb(DBusPendingCall *pending, void *user_data)
207 {
208         DBusMessage *reply;
209         DBusError error;
210
211         DLOG_DEBUG("Disconnect reply callback");
212         
213         dbus_error_init(&error);
214         
215         reply = dbus_pending_call_steal_reply(pending);
216         
217         if (dbus_set_error_from_message(&error, reply)) {
218                 
219                 DLOG_DEBUG("Disconnect pending call result:%s", error.name);
220                 
221                 dbus_error_free(&error);
222         }
223         
224         // No need to notify, wpa_supplicant will signal that for us
225         
226         if (reply)
227                 dbus_message_unref(reply);
228         dbus_pending_call_unref(pending);
229 }
230
231 void wlan_disconnect()
232 {
233         DBusMessage *msg;
234         DBusPendingCall *pending;
235         
236         DLOG_DEBUG("%s", __func__);
237         
238         msg = new_dbus_method_call(
239                 WLANCOND_SERVICE,
240                 WLANCOND_REQ_PATH,
241                 WLANCOND_REQ_INTERFACE,
242                 WLANCOND_DISCONNECT_REQ);
243
244         if (!dbus_connection_send_with_reply(get_dbus_connection(), 
245                                              msg, &pending, -1))
246                 die("Out of memory");
247         
248         if (!dbus_pending_call_set_notify(pending, disconnect_reply_cb, NULL, NULL))
249                 die("Out of memory");
250         
251         dbus_message_unref(msg);
252 }
253
254 /* -- STATUS -- */
255
256 static wlan_status_reply status_cb;
257
258 static void status_reply_cb(DBusPendingCall *pending, void *user_data)
259 {
260         DBusMessage *reply;
261         DBusError error;
262
263         DLOG_DEBUG("%s", __func__);
264         
265         dbus_error_init(&error);
266         
267         reply = dbus_pending_call_steal_reply(pending);
268         
269         if (dbus_set_error_from_message(&error, reply)) {
270                 
271                 DLOG_DEBUG("%s error: %s", __func__, error.name);
272                 goto dbus_error;
273         } else if (reply) {
274                 char *essid, *bssid, *ifname;
275                 int essid_len, bssid_len;
276                 unsigned long sens, channel, capability, security;
277                 
278                 if (!dbus_message_get_args(
279                         reply, &error,        
280                         DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &essid, &essid_len,
281                         DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &bssid, &bssid_len,
282                         DBUS_TYPE_UINT32, &sens,
283                         DBUS_TYPE_UINT32, &channel,
284                         DBUS_TYPE_UINT32, &capability,
285                         DBUS_TYPE_UINT32, &security,
286                         DBUS_TYPE_STRING, &ifname,
287                         DBUS_TYPE_INVALID)) 
288                 {
289                         DLOG_DEBUG("%s parse reply error: %s", __func__, 
290                                 error.name);
291                         goto dbus_error;
292                 }
293                 
294                 status_cb(0, essid, essid_len, bssid, bssid_len,
295                         sens, channel, capability, security,
296                         ifname);
297         }
298         
299         if (reply) 
300                 dbus_message_unref(reply);
301         dbus_pending_call_unref(pending);
302         
303         return;
304 dbus_error:
305         status_cb(-1, NULL, 0, NULL, 0,
306                         0, 0, 0, 0,
307                         error.name);
308         dbus_error_free(&error);
309         
310         if (reply) 
311                 dbus_message_unref(reply);
312         dbus_pending_call_unref(pending);
313 }
314
315 void wlan_get_status(wlan_status_reply reply_cb)
316 {
317         DBusMessage *msg;
318         DBusPendingCall *pending;
319         
320         DLOG_DEBUG("%s", __func__);
321         
322         status_cb = reply_cb;
323         
324         msg = new_dbus_method_call(
325                 WLANCOND_SERVICE,
326                 WLANCOND_REQ_PATH,
327                 WLANCOND_REQ_INTERFACE,
328                 WLANCOND_STATUS_REQ);
329
330         if (!dbus_connection_send_with_reply(get_dbus_connection(), 
331                                              msg, &pending, -1))
332                 die("Out of memory");
333         
334         if (!dbus_pending_call_set_notify(pending, status_reply_cb, NULL, NULL))
335                 die("Out of memory");
336         
337         dbus_message_unref(msg);
338 }
339