blob: 610f28504a69eae6ee1cf9f44734aea1ebb190cc [file] [log] [blame]
/*
*
* Connection Manager
*
* Copyright (C) 2007-2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gdbus.h>
#include "connman.h"
#define _DBG_NOTIFIER(fmt, arg...) DBG(DBG_NOTIFIER, fmt, ## arg)
static DBusConnection *connection = NULL;
static GSList *notifier_list = NULL;
static gint compare_priority(gconstpointer a, gconstpointer b)
{
const struct connman_notifier *notifier1 = a;
const struct connman_notifier *notifier2 = b;
return notifier2->priority - notifier1->priority;
}
/**
* connman_notifier_register:
* @notifier: notifier module
*
* Register a new notifier module
*
* Returns: %0 on success
*/
int connman_notifier_register(struct connman_notifier *notifier)
{
_DBG_NOTIFIER("notifier %p name %s", notifier, notifier->name);
/* TODO(sleffler) check return value */
notifier_list = g_slist_insert_sorted(notifier_list, notifier,
compare_priority);
return 0;
}
/**
* connman_notifier_unregister:
* @notifier: notifier module
*
* Remove a previously registered notifier module
*/
void connman_notifier_unregister(struct connman_notifier *notifier)
{
_DBG_NOTIFIER("notifier %p name %s", notifier, notifier->name);
notifier_list = g_slist_remove(notifier_list, notifier);
}
#define MAX_TECHNOLOGIES 10
static volatile gint registered[MAX_TECHNOLOGIES];
static volatile gint enabled[MAX_TECHNOLOGIES];
static volatile gint connected[MAX_TECHNOLOGIES];
static connman_bool_t istracked(enum connman_service_type type)
{
switch (type) {
case CONNMAN_SERVICE_TYPE_ETHERNET:
case CONNMAN_SERVICE_TYPE_WIFI:
case CONNMAN_SERVICE_TYPE_WIMAX:
case CONNMAN_SERVICE_TYPE_BLUETOOTH:
case CONNMAN_SERVICE_TYPE_CELLULAR:
return TRUE;
default:
return FALSE;
}
}
static void append_list(DBusMessageIter *iter, volatile gint array[])
{
static const char *type_names[] = {
[CONNMAN_SERVICE_TYPE_ETHERNET] = "ethernet",
[CONNMAN_SERVICE_TYPE_WIFI] = "wifi",
[CONNMAN_SERVICE_TYPE_WIMAX] = "wimax",
[CONNMAN_SERVICE_TYPE_BLUETOOTH] = "bluetooth",
[CONNMAN_SERVICE_TYPE_CELLULAR] = "cellular",
[CONNMAN_SERVICE_TYPE_VPN] = "vpn",
};
int i;
for (i = 0; i < MAX_TECHNOLOGIES; i++) {
if (istracked(i) && g_atomic_int_get(&array[i]) > 0)
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
&type_names[i]);
}
}
void __connman_notifier_list_registered(DBusMessageIter *iter, void *arg)
{
append_list(iter, registered);
}
void __connman_notifier_list_enabled(DBusMessageIter *iter, void *arg)
{
append_list(iter, enabled);
}
void __connman_notifier_list_connected(DBusMessageIter *iter, void *arg)
{
append_list(iter, connected);
}
static void technology_registered(enum connman_service_type type)
{
connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "AvailableTechnologies",
DBUS_TYPE_STRING, __connman_notifier_list_registered, NULL);
}
void __connman_notifier_register(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
if (istracked(type) &&
g_atomic_int_add(&registered[type], 1) == 0)
technology_registered(type);
}
void __connman_notifier_unregister(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
if (istracked(type) &&
g_atomic_int_dec_and_test(&registered[type]) == TRUE) {
technology_registered(type);
}
}
static void technology_enabled(enum connman_service_type type,
connman_bool_t enabled)
{
GSList *list;
_DBG_NOTIFIER("type %d enabled %d", type, enabled);
connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "EnabledTechnologies",
DBUS_TYPE_STRING, __connman_notifier_list_enabled, NULL);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->service_enabled != NULL)
notifier->service_enabled(type, enabled);
}
}
void __connman_notifier_enable(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
if (istracked(type) &&
g_atomic_int_add(&enabled[type], 1) == 0) {
technology_enabled(type, TRUE);
}
}
void __connman_notifier_disable(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
if (istracked(type) &&
g_atomic_int_dec_and_test(&enabled[type]) == TRUE) {
technology_enabled(type, FALSE);
}
}
static void technology_connected(enum connman_service_type type)
{
connman_dbus_send_property_changed_array(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "ConnectedTechnologies",
DBUS_TYPE_STRING, __connman_notifier_list_connected, NULL);
}
void __connman_notifier_connect(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
if (istracked(type) &&
g_atomic_int_add(&connected[type], 1) == 0) {
technology_connected(type);
}
}
void __connman_notifier_disconnect(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
if (istracked(type) &&
g_atomic_int_dec_and_test(&connected[type]) == TRUE) {
technology_connected(type);
}
}
void __connman_notifier_offlinemode(connman_bool_t enabled)
{
GSList *list;
_DBG_NOTIFIER("enabled %d", enabled);
connman_dbus_send_property_changed_variant(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "OfflineMode",
DBUS_TYPE_BOOLEAN, &enabled);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->offline_mode)
notifier->offline_mode(enabled);
}
}
void __connman_notifier_country_changed(const char *country)
{
GSList *list;
_DBG_NOTIFIER("country %s", country);
connman_dbus_send_property_changed_variant(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "Country",
DBUS_TYPE_STRING, &country);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->country_changed)
notifier->country_changed(country);
}
}
connman_bool_t __connman_notifier_is_enabled(enum connman_service_type type)
{
_DBG_NOTIFIER("type %d", type);
return (istracked(type) && g_atomic_int_get(&enabled[type]) > 0);
}
void __connman_notifier_default_changed(struct connman_service *service)
{
const char *str = connman_service_get_type(service);
GSList *list;
_DBG_NOTIFIER("service %p str \"%s\"", service, str);
connman_dbus_send_property_changed_variant(CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE, "DefaultTechnology",
DBUS_TYPE_STRING, &str);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->default_changed != NULL)
notifier->default_changed(service);
}
}
void __connman_notifier_service_state_changed(struct connman_service *service)
{
GSList *list;
_DBG_NOTIFIER("service %p", service);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->service_state_changed != NULL)
notifier->service_state_changed(service);
}
}
void __connman_notifier_system_suspend(void)
{
GSList *list;
_DBG_NOTIFIER("");
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->system_suspend != NULL)
notifier->system_suspend();
}
}
void __connman_notifier_system_resume(void)
{
GSList *list;
_DBG_NOTIFIER("");
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->system_resume != NULL)
notifier->system_resume();
}
}
void __connman_notifier_system_shutdown(void)
{
GSList *list;
_DBG_NOTIFIER("");
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->system_shutdown != NULL)
notifier->system_shutdown();
}
}
void __connman_notifier_profile_push(struct connman_profile *profile)
{
GSList *list;
_DBG_NOTIFIER("profile %p", profile);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->profile_push != NULL)
notifier->profile_push(profile);
}
}
void __connman_notifier_profile_pop(struct connman_profile *profile)
{
GSList *list;
_DBG_NOTIFIER("profile %p", profile);
for (list = notifier_list; list; list = list->next) {
struct connman_notifier *notifier = list->data;
if (notifier->profile_pop != NULL)
notifier->profile_pop(profile);
}
}
int __connman_notifier_init(void)
{
connection = connman_dbus_get_connection();
return 0;
}
void __connman_notifier_cleanup(void)
{
dbus_connection_unref(connection);
}