initial import
[libicd-wpa] / wlan.c
diff --git a/wlan.c b/wlan.c
new file mode 100644 (file)
index 0000000..659e922
--- /dev/null
+++ b/wlan.c
@@ -0,0 +1,339 @@
+/**
+  @file wlan.c
+
+  Copyright (C) 2004 Nokia Corporation. All rights reserved.
+  
+  Copyright (C) 2009 Javier S. Pedro
+
+  @author Janne Ylalehto <janne.ylalehto@nokia.com>
+  @author Johan Hedberg <johan.hedberg@nokia.com> 
+  
+  @author Javier S. Pedro <javispedro@javispedro.com>
+
+  This file is part of libicd-network-wpa.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the
+  Free Software Foundation; either version 2 of the License, or (at your
+  option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along
+  with this program; if not, write to the Free Software Foundation, Inc.,
+  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+*/
+
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include <wlancond.h>
+#include <wlancond-dbus.h>
+#include <wlancond-supp.h>
+
+#include "common.h"
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "wlan.h"
+#include "log.h"
+/* -- SCANNING -- */
+
+static wlan_found_ap found_ap_cb = NULL;
+
+int wlan_scan(const char * ssid, wlan_found_ap new_found_ap_cb)
+{
+        DBusMessage *msg, *reply;
+        DBusError error;
+        
+        DLOG_DEBUG("%s: %s (active)", __func__, ssid);
+        
+        dbus_error_init(&error);
+        
+        found_ap_cb = new_found_ap_cb;
+        
+        msg = new_dbus_method_call(
+                WLANCOND_SERVICE,
+                WLANCOND_REQ_PATH,
+                WLANCOND_REQ_INTERFACE,
+                WLANCOND_SCAN_REQ);
+        
+        gint32 power_level = WLANCOND_TX_POWER100;
+        guint32 flags = 0;
+        
+        append_dbus_args(
+                msg,
+               DBUS_TYPE_INT32, &power_level,
+               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, strlen(ssid) + 1,
+               DBUS_TYPE_UINT32, &flags,
+               
+                DBUS_TYPE_INVALID);
+
+       reply = dbus_connection_send_with_reply_and_block(get_dbus_connection(),
+                       msg, -1, &error);
+       
+       dbus_message_unref(msg);
+               
+       if (reply) {
+               DLOG_DEBUG("Scan reply OK");
+               dbus_message_unref(reply);
+               
+               return 0;
+       } else if (dbus_error_is_set(&error)) {
+               DLOG_INFO("Scan pending call result:%s", error.name);
+                dbus_error_free(&error);
+                found_ap_cb = NULL;
+                return -1;
+        } else {
+               DLOG_WARN("Scan without reply");
+               found_ap_cb = NULL;
+               return -1;
+       } 
+}
+
+gboolean wlan_is_scanning()
+{      
+       return found_ap_cb ? TRUE : FALSE;
+}
+
+void wlan_notify_ap(const char *ssid, const char *bssid,
+       int rssi, unsigned int channel, unsigned int cap_bits)
+{      
+       if (found_ap_cb)
+               found_ap_cb(SEARCH_CONTINUE, ssid, bssid, rssi / 2 - 110);
+}
+
+void wlan_notify_end_of_search()
+{      
+       wlan_found_ap prev_found_ap_cb = found_ap_cb;
+       found_ap_cb = NULL;
+       
+       // A new search may be started right after calling this callback
+       
+       if (prev_found_ap_cb)
+               prev_found_ap_cb(SEARCH_FINISHED, NULL, NULL, 0);
+}
+
+/* - CONNECTING - */
+
+static wlan_connected connected_cb;
+
+static void connect_reply_cb(DBusPendingCall *pending, void *user_data)
+{
+        DBusMessage *reply;
+        DBusError error;
+
+        DLOG_DEBUG("Connect reply callback");
+        
+        dbus_error_init(&error);
+        
+        reply = dbus_pending_call_steal_reply(pending);
+        
+        if (dbus_set_error_from_message(&error, reply)) {
+                
+                DLOG_DEBUG("Connect pending call result:%s", error.name);
+                
+                connected_cb(-1, error.name);
+                dbus_error_free(&error);
+        } else if (reply) {
+               connected_cb(0, NULL);
+        }
+        
+        if (reply) 
+                dbus_message_unref(reply);
+        dbus_pending_call_unref(pending);
+}
+
+void wlan_connect(const char * ssid, wlan_connected _connected_cb)
+{
+        DBusMessage *msg;
+        DBusPendingCall *pending;
+        
+        DLOG_DEBUG("%s: %s", __func__, ssid);
+        
+        connected_cb = _connected_cb;
+        
+        msg = new_dbus_method_call(
+                WLANCOND_SERVICE,
+                WLANCOND_REQ_PATH,
+                WLANCOND_REQ_INTERFACE,
+                WLANCOND_SETTINGS_AND_CONNECT_REQ);
+        
+        guint32 dummy = 0;
+        guint32 *dummyP = &dummy;
+        
+        gint32 power_level, mode, encryption, default_key;
+        guint32 adhoc_channel, flags;
+        
+        power_level = WLANCOND_TX_POWER100;
+        mode = WLANCOND_INFRA;
+        encryption = 0;
+        default_key = 0;
+        adhoc_channel = 0;
+        flags = WLANCOND_USE_SUPPLICANT;
+        
+        append_dbus_args(
+                msg,
+               DBUS_TYPE_INT32, &power_level,
+               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &ssid, strlen(ssid),
+               DBUS_TYPE_INT32, &mode,
+               DBUS_TYPE_INT32, &encryption,
+               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
+               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
+               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
+               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &dummyP, 0,
+               DBUS_TYPE_INT32, &default_key,
+               DBUS_TYPE_UINT32, &adhoc_channel,
+               DBUS_TYPE_UINT32, &flags,               
+                DBUS_TYPE_INVALID);
+
+        if (!dbus_connection_send_with_reply(get_dbus_connection(), 
+                                             msg, &pending, -1))
+                die("Out of memory");
+        
+        if (!dbus_pending_call_set_notify(pending, connect_reply_cb, NULL, NULL))
+                die("Out of memory");
+        
+        dbus_message_unref(msg);
+}
+
+static void disconnect_reply_cb(DBusPendingCall *pending, void *user_data)
+{
+        DBusMessage *reply;
+        DBusError error;
+
+        DLOG_DEBUG("Disconnect reply callback");
+        
+        dbus_error_init(&error);
+        
+        reply = dbus_pending_call_steal_reply(pending);
+        
+        if (dbus_set_error_from_message(&error, reply)) {
+                
+                DLOG_DEBUG("Disconnect pending call result:%s", error.name);
+                
+                dbus_error_free(&error);
+        }
+        
+       // No need to notify, wpa_supplicant will signal that for us
+        
+        if (reply)
+                dbus_message_unref(reply);
+        dbus_pending_call_unref(pending);
+}
+
+void wlan_disconnect()
+{
+        DBusMessage *msg;
+        DBusPendingCall *pending;
+        
+       DLOG_DEBUG("%s", __func__);
+        
+        msg = new_dbus_method_call(
+                WLANCOND_SERVICE,
+                WLANCOND_REQ_PATH,
+                WLANCOND_REQ_INTERFACE,
+                WLANCOND_DISCONNECT_REQ);
+
+        if (!dbus_connection_send_with_reply(get_dbus_connection(), 
+                                             msg, &pending, -1))
+                die("Out of memory");
+        
+        if (!dbus_pending_call_set_notify(pending, disconnect_reply_cb, NULL, NULL))
+                die("Out of memory");
+        
+        dbus_message_unref(msg);
+}
+
+/* -- STATUS -- */
+
+static wlan_status_reply status_cb;
+
+static void status_reply_cb(DBusPendingCall *pending, void *user_data)
+{
+        DBusMessage *reply;
+        DBusError error;
+
+        DLOG_DEBUG("%s", __func__);
+        
+        dbus_error_init(&error);
+        
+        reply = dbus_pending_call_steal_reply(pending);
+        
+        if (dbus_set_error_from_message(&error, reply)) {
+                
+                DLOG_DEBUG("%s error: %s", __func__, error.name);
+                goto dbus_error;
+        } else if (reply) {
+               char *essid, *bssid, *ifname;
+               int essid_len, bssid_len;
+               unsigned long sens, channel, capability, security;
+               
+               if (!dbus_message_get_args(
+                       reply, &error,        
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &essid, &essid_len,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &bssid, &bssid_len,
+                       DBUS_TYPE_UINT32, &sens,
+                       DBUS_TYPE_UINT32, &channel,
+                       DBUS_TYPE_UINT32, &capability,
+                       DBUS_TYPE_UINT32, &security,
+                       DBUS_TYPE_STRING, &ifname,
+                       DBUS_TYPE_INVALID)) 
+               {
+                       DLOG_DEBUG("%s parse reply error: %s", __func__, 
+                               error.name);
+                       goto dbus_error;
+               }
+               
+               status_cb(0, essid, essid_len, bssid, bssid_len,
+                       sens, channel, capability, security,
+                       ifname);
+        }
+        
+        if (reply) 
+                dbus_message_unref(reply);
+        dbus_pending_call_unref(pending);
+        
+        return;
+dbus_error:
+       status_cb(-1, NULL, 0, NULL, 0,
+                       0, 0, 0, 0,
+                       error.name);
+       dbus_error_free(&error);
+       
+       if (reply) 
+                dbus_message_unref(reply);
+        dbus_pending_call_unref(pending);
+}
+
+void wlan_get_status(wlan_status_reply reply_cb)
+{
+        DBusMessage *msg;
+        DBusPendingCall *pending;
+        
+       DLOG_DEBUG("%s", __func__);
+        
+        status_cb = reply_cb;
+        
+        msg = new_dbus_method_call(
+                WLANCOND_SERVICE,
+                WLANCOND_REQ_PATH,
+                WLANCOND_REQ_INTERFACE,
+                WLANCOND_STATUS_REQ);
+
+        if (!dbus_connection_send_with_reply(get_dbus_connection(), 
+                                             msg, &pending, -1))
+                die("Out of memory");
+        
+        if (!dbus_pending_call_set_notify(pending, status_reply_cb, NULL, NULL))
+                die("Out of memory");
+        
+        dbus_message_unref(msg);
+}
+