/* diversity-nm-backend - Scan for new networks with NetworkManager * * Copyright 2007-2008 OpenMoko, Inc. * Authored by Stefan Schmidt * * 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 #include #include #include #include "NetworkManager.h" #include "nm-client.h" #include "nm-device.h" static struct { DiversityWorld *world; NMClient *client; /* assume there are at most one device for each type */ NMDevice *wired_device; NMDevice *wireless_device; } nm; void nm_update_strength_grid(DiversityAp *ap, gint8 strength) { gdouble lon, lat; diversity_world_get_position(nm.world, &lon, &lat); diversity_ap_update_strength_grid(ap, lon, lat, strength); } static void position_ap(DiversityAp *ap) { gdouble lon, lat, len; diversity_world_get_position(nm.world, &lon, &lat); len = DIVERSITY_UNITS(200); lon -= len / 2; lat -= len / 2; diversity_object_geometry_set(DIVERSITY_OBJECT(ap), lon, lat, len, len); } static void monitor_ap(DiversityAp *new_ap, NMDevice *dev) { DiversityAp *ap; const gchar *id, *act = "updated"; /* unique? */ id = diversity_ap_get_hw_address(new_ap); ap = (DiversityAp *) diversity_world_lookup_object(nm.world, DIVERSITY_OBJECT_TYPE_AP, id); if (!ap) { ap = new_ap; DIVERSITY_OBJECT(ap)->id = g_strdup(id); position_ap(ap); diversity_world_add_object(nm.world, DIVERSITY_OBJECT(ap)); act = "added"; } else if (ap != new_ap) { diversity_ap_merge(ap, new_ap); nm_device_replace_ap(dev, new_ap, ap); act = "substituted"; } nm_update_strength_grid(ap, diversity_ap_get_strength(ap)); g_print("%s ap(%s) %s: %c%s %i%% (on %dMHz)\n", dev->iface, id, act, diversity_ap_get_flags(ap) ? '*' : ' ', diversity_ap_get_ssid(ap), diversity_ap_get_strength(ap), diversity_ap_get_frequency(ap)); } static void on_access_point_added(NMDevice *dev, DiversityAp *ap, gpointer data) { diversity_ap_set_in_service(ap, TRUE); monitor_ap(ap, dev); } static void on_access_point_removed(NMDevice *dev, DiversityAp *ap, gpointer data) { const gchar *ssid; diversity_ap_set_in_service(ap, FALSE); ssid = diversity_ap_get_ssid(ap); g_print("%s ap removed: %s\n", dev->iface, ssid); } inline static DiversityNetworkDetail state_to_detail(NMDeviceState state) { DiversityNetworkDetail detail; switch (state) { case NM_DEVICE_STATE_UNKNOWN: detail = DIVERSITY_NETWORK_DETAIL_UNKNOWN; break; case NM_DEVICE_STATE_DOWN: detail = DIVERSITY_NETWORK_DETAIL_DOWN; break; case NM_DEVICE_STATE_DISCONNECTED: detail = DIVERSITY_NETWORK_DETAIL_DISCONNECTED; break; case NM_DEVICE_STATE_PREPARE: detail = DIVERSITY_NETWORK_DETAIL_PREPARE; break; case NM_DEVICE_STATE_CONFIG: detail = DIVERSITY_NETWORK_DETAIL_CONFIG; break; case NM_DEVICE_STATE_NEED_AUTH: detail = DIVERSITY_NETWORK_DETAIL_NEED_AUTH; break; case NM_DEVICE_STATE_IP_CONFIG: detail = DIVERSITY_NETWORK_DETAIL_IP_CONFIG; break; case NM_DEVICE_STATE_ACTIVATED: detail = DIVERSITY_NETWORK_DETAIL_ACTIVATED; break; case NM_DEVICE_STATE_FAILED: detail = DIVERSITY_NETWORK_DETAIL_FAILED; break; case NM_DEVICE_STATE_CANCELLED: detail = DIVERSITY_NETWORK_DETAIL_CANCELLED; break; default: detail = DIVERSITY_NETWORK_DETAIL_UNKNOWN; break; } return (DiversityNetworkDetail) state; } static void on_device_state_changed(NMDevice *dev, NMDeviceState state, gpointer data) { DiversityAp *ap = NULL; diversity_world_network_set_detail(nm.world, state_to_detail(state)); if (dev->type == DEVICE_TYPE_802_11_WIRELESS && (dev->state >= NM_DEVICE_STATE_PREPARE && dev->state <= NM_DEVICE_STATE_ACTIVATED)) ap = nm_device_get_active_access_point(dev); diversity_world_network_set_ap(nm.world, ap); g_print("%s state: %d\n", dev->iface, state); g_print("active ap: %s\n", (ap) ? diversity_ap_get_ssid(ap) : NULL); } static void monitor_device(NMDevice *dev) { GSList *aps, *tmp_list; aps = nm_device_get_access_points(dev); tmp_list = aps; while (tmp_list) { monitor_ap(tmp_list->data, dev); tmp_list = tmp_list->next; } g_slist_free(aps); g_signal_connect(dev, "state-changed", G_CALLBACK(on_device_state_changed), NULL); g_signal_connect(dev, "access-point-added", G_CALLBACK(on_access_point_added), NULL); g_signal_connect(dev, "access-point-removed", G_CALLBACK(on_access_point_removed), NULL); } static void on_device_added(NMClient *client, NMDevice *dev, gpointer data) { if (!nm.wired_device && dev->type == DEVICE_TYPE_802_3_ETHERNET) nm.wired_device = dev; if (!nm.wireless_device && dev->type == DEVICE_TYPE_802_11_WIRELESS) nm.wireless_device = dev; diversity_world_network_set_capabilities(nm.world, nm.wired_device != NULL, nm.wireless_device != NULL); monitor_device(dev); } static void on_device_removed(NMClient *client, NMDevice *dev, gpointer data) { if (nm.wired_device == dev) nm.wired_device = NULL; if (nm.wireless_device == dev) nm.wireless_device = NULL; diversity_world_network_set_capabilities(nm.world, nm.wired_device != NULL, nm.wireless_device != NULL); g_print("%s removed\n", dev->iface); } static void on_client_state_changed(NMClient *client, NMState state, gpointer data) { gchar *state_string = NULL; switch (state) { case NM_STATE_ASLEEP: state_string = "asleep"; diversity_world_network_set_state(nm.world, DIVERSITY_NETWORK_STATE_ASLEEP); break; case NM_STATE_CONNECTING: state_string = "connecting"; diversity_world_network_set_state(nm.world, DIVERSITY_NETWORK_STATE_CONNECTING); break; case NM_STATE_CONNECTED: state_string = "connected"; diversity_world_network_set_state(nm.world, DIVERSITY_NETWORK_STATE_CONNECTED); break; case NM_STATE_DISCONNECTED: state_string = "disconnected"; diversity_world_network_set_state(nm.world, DIVERSITY_NETWORK_STATE_DISCONNECTED); break; case NM_STATE_UNKNOWN: default: state_string = "unknown"; diversity_world_network_set_state(nm.world, DIVERSITY_NETWORK_STATE_UNKNOWN); break; } g_print("NM State: %s\n", state_string); } static void on_manager_running(NMClient *client, gboolean running, gpointer data) { if (running) on_client_state_changed(nm.client, nm_client_get_state(nm.client), NULL); else on_client_state_changed(client, NM_STATE_UNKNOWN, NULL); g_print("NM Running: %d\n", running); } static void nm_connect_ap(DiversityNetwork *network, DiversityAp *ap) { if (nm.wireless_device) nm_client_activate_device(nm.client, nm.wireless_device, ap); } static void nm_connect_wired(DiversityNetwork *network) { if (nm.wired_device) nm_client_activate_device(nm.client, nm.wired_device, NULL); } static void nm_sleep(DiversityNetwork *network, gboolean sleep) { nm_client_sleep(nm.client, sleep); } int nm_init(DiversityWorld *world, GError **error) { if (!g_thread_supported()) { g_thread_init(NULL); dbus_g_thread_init(); } nm.world = world; nm.client = nm_client_new(); nm.wired_device = NULL; nm.wireless_device = NULL; diversity_world_network_set_interface(nm.world, nm_connect_ap, nm_connect_wired, nm_sleep, NULL); g_signal_connect(nm.client, "state-change", G_CALLBACK(on_client_state_changed), NULL); g_signal_connect(nm.client, "manager-running", G_CALLBACK(on_manager_running), NULL); g_signal_connect(nm.client, "device-added", G_CALLBACK(on_device_added), NULL); g_signal_connect(nm.client, "device-removed", G_CALLBACK(on_device_removed), NULL); on_manager_running(nm.client, nm_client_manager_is_running(nm.client), NULL); { GSList *devs, *tmp_list; devs = nm_client_get_devices(nm.client); tmp_list = devs; while (tmp_list) { on_device_added(nm.client, tmp_list->data, NULL); tmp_list = tmp_list->next; } g_slist_free(devs); } return TRUE; } void nm_fini(void) { g_object_unref(nm.client); }