enlightenment/src/modules/connman/e_iface.c

1349 lines
38 KiB
C

#include "e_iface.h"
/* IFACE INTERNALS */
static E_DBus_Connection *conn = NULL;
static Evas_List *callbacks = NULL;
static E_DBus_Signal_Handler *sigh_name_ownerchanged = NULL;
static E_DBus_Signal_Handler *sigh_interface_added = NULL;
static E_DBus_Signal_Handler *sigh_interface_removed = NULL;
static Evas_List *interfaces = NULL;
static Evas_List *
iface_callback(Evas_List *callbacks, Interface_Event event, Interface *iface, Interface_Network *ifnet)
{
Evas_List *l;
Evas_List *deletes = NULL;
for (l = callbacks; l; l = l->next)
{
Interface_Callback *cb;
cb = l->data;
if (cb->delete_me)
{
deletes = evas_list_append(deletes, l->data);
continue;
}
if (cb->event == event)
cb->func(cb->data, iface, ifnet);
}
while (deletes)
{
callbacks = evas_list_remove(callbacks, deletes->data);
free(deletes->data);
deletes = evas_list_remove_list(deletes, deletes);
}
return callbacks;
}
static Interface_IPv4 *
iface_ipv4_decode(DBusMessage *msg)
{
DBusMessageIter array, iter, item, val;
Interface_IPv4 *d;
d = calloc(1, sizeof(Interface_IPv4));
if (!d) return NULL;
if (dbus_message_iter_init(msg, &array))
{
if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY)
{
dbus_message_iter_recurse(&array, &iter);
while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_DICT_ENTRY)
{
char *key, *v;
int sig;
int type;
dbus_message_iter_recurse(&iter, &item);
key = NULL;
dbus_message_iter_get_basic(&item, &key);
dbus_message_iter_next(&item);
dbus_message_iter_recurse(&item, &val);
type = dbus_message_iter_get_arg_type(&val);
v = NULL;
if ((!strcmp(key, "Method")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->method = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Address")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->address = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Gateway")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->gateway = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Netmask")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->netmask = evas_stringshare_add(v);
}
dbus_message_iter_next(&iter);
}
}
}
return d;
}
static void *
iface_getipv4_unmarhsall(DBusMessage *msg, DBusError *err)
{
return iface_ipv4_decode(msg);
}
static void
iface_getipv4_callback(void *data, void *ret, DBusError *err)
{
Interface *iface = data;
Interface_IPv4 *d = ret;
if (!d)
{
iface_unref(iface);
return;
}
if (iface->ipv4.method) evas_stringshare_del(iface->ipv4.method);
if (iface->ipv4.address) evas_stringshare_del(iface->ipv4.address);
if (iface->ipv4.gateway) evas_stringshare_del(iface->ipv4.gateway);
if (iface->ipv4.netmask) evas_stringshare_del(iface->ipv4.netmask);
memcpy(&(iface->ipv4), d, sizeof(Interface_IPv4));
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_IPV4_CHANGE,
iface, NULL);
iface_unref(iface);
}
static void
iface_getipv4_result_free(void *data)
{
Interface_IPv4 *d = data;
free(d);
}
static Interface_Network_Selection *
iface_network_selection_decode(DBusMessage *msg)
{
DBusMessageIter array, iter, item, val;
Interface_Network_Selection *d;
d = calloc(1, sizeof(Interface_Network_Selection));
if (!d) return NULL;
if (dbus_message_iter_init(msg, &array))
{
if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY)
{
dbus_message_iter_recurse(&array, &iter);
while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_DICT_ENTRY)
{
char *key, *v;
int sig;
int type;
dbus_message_iter_recurse(&iter, &item);
key = NULL;
dbus_message_iter_get_basic(&item, &key);
dbus_message_iter_next(&item);
dbus_message_iter_recurse(&item, &val);
type = dbus_message_iter_get_arg_type(&val);
v = NULL;
if ((!strcmp(key, "ESSID")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->id = evas_stringshare_add(v);
}
else if ((!strcmp(key, "PSK")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->pass = evas_stringshare_add(v);
}
dbus_message_iter_next(&iter);
}
}
}
return d;
}
static void *
iface_getnetwork_unmarhsall(DBusMessage *msg, DBusError *err)
{
return iface_network_selection_decode(msg);
}
static void
iface_getnetwork_callback(void *data, void *ret, DBusError *err)
{
Interface *iface = data;
Interface_Network_Selection *d = ret;
if (!d)
{
iface_unref(iface);
return;
}
if (iface->network_selection.id) evas_stringshare_del(iface->network_selection.id);
if (iface->network_selection.pass) evas_stringshare_del(iface->network_selection.pass);
memcpy(&(iface->network_selection), d, sizeof(Interface_Network_Selection));
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_NETWORK_SELECTION_CHANGE,
iface, NULL);
iface_unref(iface);
}
static void
iface_getnetwork_result_free(void *data)
{
Interface_IPv4 *d = data;
free(d);
}
static void *
iface_getproperties_unmarhsall(DBusMessage *msg, DBusError *err)
{
DBusMessageIter array, iter, item, val;
Interface_Properties *d;
d = calloc(1, sizeof(Interface_Properties));
if (!d) return NULL;
if (dbus_message_iter_init(msg, &array))
{
if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY)
{
dbus_message_iter_recurse(&array, &iter);
while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_DICT_ENTRY)
{
char *key, *v;
int sig;
int type;
dbus_message_iter_recurse(&iter, &item);
key = NULL;
dbus_message_iter_get_basic(&item, &key);
dbus_message_iter_next(&item);
dbus_message_iter_recurse(&item, &val);
type = dbus_message_iter_get_arg_type(&val);
v = NULL;
if ((!strcmp(key, "Type")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->type = evas_stringshare_add(v);
}
else if ((!strcmp(key, "State")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->state = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Policy")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->policy = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Driver")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->driver = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Vendor")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->vendor = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Product")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) d->product = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Signal")) && (type == DBUS_TYPE_UINT16))
{
dbus_uint16_t vi;
dbus_message_iter_get_basic(&val, &vi);
d->signal_strength = vi;
}
dbus_message_iter_next(&iter);
}
}
}
return d;
}
static void
iface_getproperties_callback(void *data, void *ret, DBusError *err)
{
Interface *iface = data;
Interface_Properties *d = ret;
if (!d)
{
iface_unref(iface);
iface_unref(iface);
return;
}
if (iface->prop.product) evas_stringshare_del(iface->prop.product);
if (iface->prop.vendor) evas_stringshare_del(iface->prop.vendor);
if (iface->prop.driver) evas_stringshare_del(iface->prop.driver);
if (iface->prop.state) evas_stringshare_del(iface->prop.state);
if (iface->prop.policy) evas_stringshare_del(iface->prop.policy);
if (iface->prop.type) evas_stringshare_del(iface->prop.type);
memcpy(&(iface->prop), d, sizeof(Interface_Properties));
if (!iface->newif)
{
callbacks = iface_callback(callbacks,
IFACE_EVENT_ADD,
iface, NULL);
iface->newif = 1;
}
iface_unref(iface);
}
static void
iface_getproperties_result_free(void *data)
{
Interface_Properties *d = data;
free(d);
}
static void
iface_net_add(Interface *iface, const char *essid, const char *bssid, int signal_strength, const char *security)
{
Interface_Network *net;
Evas_List *l;
for (l = iface->networks; l; l = l->next)
{
net = l->data;
if (!strcmp(bssid, net->bssid))
{
int changes = 0;
net->last_seen_time = ecore_time_get();
if (((essid) && (net->essid) &&
(!strcmp(essid, net->essid))) ||
(!!essid != !!net->essid))
{
if (net->essid) evas_stringshare_del(net->essid);
if (essid) net->essid = evas_stringshare_add(essid);
else net->essid = NULL;
changes++;
}
if (signal_strength != net->signal_strength)
{
net->signal_strength = signal_strength;
changes++;
}
if (((security) && (net->security) &&
(!strcmp(security, net->security))) ||
(!!security != !!net->security))
{
if (net->security) evas_stringshare_del(net->security);
if (security) net->security = evas_stringshare_add(security);
else net->security = NULL;
changes++;
}
if (changes > 0)
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_SCAN_NETWORK_CHANGE,
iface, net);
return;
}
}
net = calloc(1, sizeof(Interface_Network));
if (net)
{
net->last_seen_time = ecore_time_get();
if (essid) net->essid = evas_stringshare_add(essid);
net->bssid = evas_stringshare_add(bssid);
net->signal_strength = signal_strength;
if (security) net->security = evas_stringshare_add(security);
iface->networks = evas_list_append(iface->networks, net);
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_SCAN_NETWORK_ADD,
iface, net);
}
}
static void
iface_sigh_network_found(void *data, DBusMessage *msg)
{
DBusError err;
Interface *iface = data;
DBusMessageIter array, iter, item, val;
Interface_Properties *d;
if (dbus_message_iter_init(msg, &array))
{
if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY)
{
Interface_Network *net;
dbus_message_iter_recurse(&array, &iter);
net = calloc(1, sizeof(Interface_Network));
if (net)
{
while (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_DICT_ENTRY)
{
char *key, *v;
int type;
dbus_message_iter_recurse(&iter, &item);
key = NULL;
dbus_message_iter_get_basic(&item, &key);
dbus_message_iter_next(&item);
dbus_message_iter_recurse(&item, &val);
type = dbus_message_iter_get_arg_type(&val);
v = NULL;
if ((!strcmp(key, "ESSID")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) net->essid = evas_stringshare_add(v);
}
else if ((!strcmp(key, "BSSID")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) net->bssid = evas_stringshare_add(v);
}
else if ((!strcmp(key, "Signal")) && (type == DBUS_TYPE_UINT16))
{
dbus_uint16_t vi;
dbus_message_iter_get_basic(&val, &vi);
net->signal_strength = vi;
}
if ((!strcmp(key, "Security")) && (type == DBUS_TYPE_STRING))
{
dbus_message_iter_get_basic(&val, &v);
if (v) net->security = evas_stringshare_add(v);
}
dbus_message_iter_next(&iter);
}
if (net->bssid)
iface_net_add(iface, net->essid, net->bssid,
net->signal_strength, net->security);
if (net->essid) evas_stringshare_del(net->essid);
if (net->bssid) evas_stringshare_del(net->bssid);
if (net->security) evas_stringshare_del(net->security);
free(net);
}
}
}
}
static void
iface_sigh_signal_changed(void *data, DBusMessage *msg)
{
DBusError err;
Interface *iface = data;
/* FIXME: need to handle signal changed - and fix connman */
/* FIXME: wpa_supplicant doesn't support this yet. see:
* mlme.c: ieee80211_associated() */
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_SIGNAL_CHANGE,
iface, NULL);
}
static void
iface_sigh_state_changed(void *data, DBusMessage *msg)
{
DBusError err;
Interface *iface = data;
DBusMessageIter iter;
const char *s = NULL;
dbus_message_iter_init(msg, &iter);
dbus_message_iter_get_basic(&iter, &(s));
if (!s) return;
if (iface->prop.state) evas_stringshare_del(iface->prop.state);
iface->prop.state = evas_stringshare_add(s);
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"GetIPv4");
if (msg)
{
e_dbus_method_call_send(conn, msg,
iface_getipv4_unmarhsall,
iface_getipv4_callback,
iface_getipv4_result_free, -1, iface);
dbus_message_unref(msg);
iface_ref(iface);
}
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_STATE_CHANGE,
iface, NULL);
}
static void
iface_sigh_policy_changed(void *data, DBusMessage *msg)
{
DBusError err;
Interface *iface = data;
DBusMessageIter iter;
const char *s = NULL;
dbus_message_iter_init(msg, &iter);
dbus_message_iter_get_basic(&iter, &(s));
if (!s) return;
if (iface->prop.policy) evas_stringshare_del(iface->prop.policy);
iface->prop.policy = evas_stringshare_add(s);
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_POLICY_CHANGE,
iface, NULL);
}
static void
iface_sigh_network_changed(void *data, DBusMessage *msg)
{
DBusError err;
Interface *iface = data;
Interface_Network_Selection *d;
d = iface_network_selection_decode(msg);
if (!d) return;
if (iface->network_selection.id) evas_stringshare_del(iface->network_selection.id);
if (iface->network_selection.pass) evas_stringshare_del(iface->network_selection.pass);
memcpy(&(iface->network_selection), d, sizeof(Interface_Network_Selection));
free(d);
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_NETWORK_SELECTION_CHANGE,
iface, NULL);
}
static void
iface_sigh_ipv4_changed(void *data, DBusMessage *msg)
{
DBusError err;
Interface *iface = data;
Interface_IPv4 *d;
d = iface_ipv4_decode(msg);
if (!d) return;
if (iface->ipv4.method) evas_stringshare_del(iface->ipv4.method);
if (iface->ipv4.address) evas_stringshare_del(iface->ipv4.address);
if (iface->ipv4.gateway) evas_stringshare_del(iface->ipv4.gateway);
if (iface->ipv4.netmask) evas_stringshare_del(iface->ipv4.netmask);
memcpy(&(iface->ipv4), d, sizeof(Interface_IPv4));
free(d);
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_IPV4_CHANGE,
iface, NULL);
}
static int
iface_timer_network_timeout(void *data)
{
Interface *iface = data;
double now;
Interface_Network *net;
Evas_List *l, *l_del;
now = ecore_time_get();
iface_ref(iface);
for (l = iface->networks; l;)
{
net = l->data;
if ((now - net->last_seen_time) > 20.0)
{
l_del = l;
l = l->next;
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_SCAN_NETWORK_DEL,
iface, net);
iface->networks = evas_list_remove_list(iface->networks, l_del);
if (net->essid) evas_stringshare_del(net->essid);
if (net->bssid) evas_stringshare_del(net->bssid);
if (net->security) evas_stringshare_del(net->security);
free(net);
}
else
l = l->next;
}
iface_unref(iface);
}
static void *
iface_system_listinterfaces_unmarhsall(DBusMessage *msg, DBusError *err)
{
DBusMessageIter array, iter;
if (dbus_message_iter_init(msg, &array))
{
if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_ARRAY)
{
dbus_message_iter_recurse(&array, &iter);
do
{
char *ifpath;
ifpath = NULL;
dbus_message_iter_get_basic(&iter, &ifpath);
if (ifpath)
{
if (!iface_find(ifpath))
{
printf("ADD 1 %s\n", ifpath);
iface_add(ifpath);
}
}
}
while (dbus_message_iter_next(&iter));
}
}
return NULL;
}
static void
iface_system_listinterfaces_callback(void *data, void *ret, DBusError *err)
{
}
static void
iface_system_listinterfaces_result_free(void *data)
{
}
static void
iface_system_added(void *data, DBusMessage *msg)
{
DBusError err;
DBusMessageIter iter;
const char *s = NULL;
dbus_message_iter_init(msg, &iter);
dbus_message_iter_get_basic(&iter, &(s));
if (!s) return;
if (iface_find(s)) return;
printf("ADD 2 %s\n", s);
iface_add(s);
}
static void
iface_system_removed(void *data, DBusMessage *msg)
{
DBusError err;
DBusMessageIter iter;
const char *s = NULL;
Interface *iface;
dbus_message_iter_init(msg, &iter);
dbus_message_iter_get_basic(&iter, &(s));
if (!s) return;
if (!(iface = iface_find(s))) return;
callbacks = iface_callback(callbacks,
IFACE_EVENT_DEL,
iface, NULL);
iface_unref(iface);
}
static void
iface_system_interfaces_list(void)
{
DBusMessage *msg;
msg = dbus_message_new_method_call("org.freedesktop.connman",
"/",
"org.freedesktop.connman.Manager",
"ListInterfaces");
if (!msg) return;
e_dbus_method_call_send(conn, msg,
iface_system_listinterfaces_unmarhsall,
iface_system_listinterfaces_callback,
iface_system_listinterfaces_result_free, -1, NULL);
dbus_message_unref(msg);
if (sigh_interface_added)
e_dbus_signal_handler_del(conn, sigh_interface_added);
sigh_interface_added = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", "/", "org.freedesktop.connman.Manager",
"InterfaceAdded", iface_system_added, NULL);
if (sigh_interface_removed)
e_dbus_signal_handler_del(conn, sigh_interface_removed);
sigh_interface_removed = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", "/", "org.freedesktop.connman.Manager",
"InterfaceRemoved", iface_system_removed, NULL);
}
static void
iface_system_name_ownerchanged(void *data, DBusMessage *msg)
{
DBusError err;
DBusMessageIter iter;
const char *s1, *s2, *s3;
dbus_error_init(&err);
if (!dbus_message_get_args(msg, &err,
DBUS_TYPE_STRING, &s1,
DBUS_TYPE_STRING, &s2,
DBUS_TYPE_STRING, &s3,
DBUS_TYPE_INVALID))
return;
if (strcmp(s1, "org.freedesktop.connman")) return;
iface_system_interfaces_list();
}
/* IFACE PUBLIC API */
Interface *
iface_add(const char *ifpath)
{
Interface *iface;
DBusMessage *msg;
iface = calloc(1, sizeof(Interface));
iface->ref = 1;
iface->ifpath = evas_stringshare_add(ifpath);
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"GetProperties");
if (!msg)
{
evas_stringshare_del(iface->ifpath);
free(iface);
return NULL;
}
e_dbus_method_call_send(conn, msg,
iface_getproperties_unmarhsall,
iface_getproperties_callback,
iface_getproperties_result_free, -1, iface);
dbus_message_unref(msg);
iface_ref(iface);
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"GetIPv4");
if (msg)
{
e_dbus_method_call_send(conn, msg,
iface_getipv4_unmarhsall,
iface_getipv4_callback,
iface_getipv4_result_free, -1, iface);
dbus_message_unref(msg);
iface_ref(iface);
}
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"GetNetwork");
if (msg)
{
e_dbus_method_call_send(conn, msg,
iface_getnetwork_unmarhsall,
iface_getnetwork_callback,
iface_getnetwork_result_free, -1, iface);
dbus_message_unref(msg);
iface_ref(iface);
}
iface->sigh.network_found = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", iface->ifpath,
"org.freedesktop.connman.Interface", "NetworkFound",
iface_sigh_network_found, iface);
iface->sigh.signal_changed = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", iface->ifpath,
"org.freedesktop.connman.Interface", "SignalChanged",
iface_sigh_signal_changed, iface);
iface->sigh.state_changed = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", iface->ifpath,
"org.freedesktop.connman.Interface", "StateChanged",
iface_sigh_state_changed, iface);
iface->sigh.policy_changed = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", iface->ifpath,
"org.freedesktop.connman.Interface", "PolicyChanged",
iface_sigh_policy_changed, iface);
iface->sigh.network_changed = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", iface->ifpath,
"org.freedesktop.connman.Interface", "NetworkChanged",
iface_sigh_network_changed, iface);
iface->sigh.ipv4_changed = e_dbus_signal_handler_add
(conn, "org.freedesktop.connman", iface->ifpath,
"org.freedesktop.connman.Interface", "IPv4Changed",
iface_sigh_ipv4_changed, iface);
iface->network_timeout = ecore_timer_add(10.0, iface_timer_network_timeout,
iface);
interfaces = evas_list_append(interfaces, iface);
return iface;
}
void
iface_ref(Interface *iface)
{
iface->ref++;
}
void
iface_unref(Interface *iface)
{
iface->ref--;
if (iface->ref != 0) return;
iface->callbacks = iface_callback(iface->callbacks,
IFACE_EVENT_DEL,
iface, NULL);
while (iface->callbacks)
{
free(iface->callbacks->data);
iface->callbacks = evas_list_remove_list(iface->callbacks, iface->callbacks);
}
if (iface->network_timeout)
ecore_timer_del(iface->network_timeout);
if (iface->network_selection.id) evas_stringshare_del(iface->network_selection.id);
if (iface->network_selection.pass) evas_stringshare_del(iface->network_selection.pass);
while (iface->networks)
{
Interface_Network *net;
net = iface->networks->data;
if (net->essid) evas_stringshare_del(net->essid);
if (net->bssid) evas_stringshare_del(net->bssid);
if (net->security) evas_stringshare_del(net->security);
free(net);
iface->networks = evas_list_remove_list(iface->networks, iface->networks);
}
if (iface->network_timeout) ecore_timer_del(iface->network_timeout);
if (iface->prop.product) evas_stringshare_del(iface->prop.product);
if (iface->prop.vendor) evas_stringshare_del(iface->prop.vendor);
if (iface->prop.driver) evas_stringshare_del(iface->prop.driver);
if (iface->prop.state) evas_stringshare_del(iface->prop.state);
if (iface->prop.policy) evas_stringshare_del(iface->prop.policy);
if (iface->prop.type) evas_stringshare_del(iface->prop.type);
e_dbus_signal_handler_del(conn, iface->sigh.network_found);
e_dbus_signal_handler_del(conn, iface->sigh.signal_changed);
e_dbus_signal_handler_del(conn, iface->sigh.state_changed);
e_dbus_signal_handler_del(conn, iface->sigh.policy_changed);
e_dbus_signal_handler_del(conn, iface->sigh.network_changed);
e_dbus_signal_handler_del(conn, iface->sigh.ipv4_changed);
interfaces = evas_list_remove(interfaces, iface);
free(iface);
}
Interface *
iface_find(const char *ifpath)
{
Evas_List *l;
if (!ifpath) return NULL;
for (l = interfaces; l; l = l->next)
{
Interface *iface;
iface = l->data;
if (!strcmp(iface->ifpath, ifpath)) return iface;
}
return NULL;
}
void
iface_network_set(Interface *iface, const char *ssid, const char *pass)
{
DBusMessage *msg;
DBusMessageIter iter, array, item, val;
const char *key;
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"SetNetwork");
if (!msg) return;
dbus_message_iter_init_append(msg, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &item);
key = "ESSID";
dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&item, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &val);
dbus_message_iter_append_basic(&val, DBUS_TYPE_STRING, &ssid);
dbus_message_iter_close_container(&item, &val);
dbus_message_iter_close_container(&array, &item);
if (pass)
{
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &item);
key = "PSK";
dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&item, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &val);
dbus_message_iter_append_basic(&val, DBUS_TYPE_STRING, &pass);
dbus_message_iter_close_container(&item, &val);
dbus_message_iter_close_container(&array, &item);
}
dbus_message_iter_close_container(&iter, &array);
e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
dbus_message_unref(msg);
}
void
iface_policy_set(Interface *iface, const char *policy)
{
DBusMessage *msg;
DBusMessageIter iter;
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"SetPolicy");
if (!msg) return;
dbus_message_iter_init_append(msg, &iter);
dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &policy);
e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
dbus_message_unref(msg);
}
void
iface_scan(Interface *iface, const char *policy)
{
DBusMessage *msg;
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"Scan");
if (!msg) return;
e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
dbus_message_unref(msg);
}
void
iface_ipv4_set(Interface *iface, const char *method, const char *address, const char *gateway, const char *netmask)
{
DBusMessage *msg;
DBusMessageIter iter, array, item, val;
const char *key;
msg = dbus_message_new_method_call("org.freedesktop.connman",
iface->ifpath,
"org.freedesktop.connman.Interface",
"SetIPv4");
if (!msg) return;
dbus_message_iter_init_append(msg, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
if (method)
{
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &item);
key = "Method";
dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&item, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &val);
dbus_message_iter_append_basic(&val, DBUS_TYPE_STRING, &method);
dbus_message_iter_close_container(&item, &val);
dbus_message_iter_close_container(&array, &item);
}
if (address)
{
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &item);
key = "Address";
dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&item, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &val);
dbus_message_iter_append_basic(&val, DBUS_TYPE_STRING, &address);
dbus_message_iter_close_container(&item, &val);
dbus_message_iter_close_container(&array, &item);
}
if (gateway)
{
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &item);
key = "Gateway";
dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&item, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &val);
dbus_message_iter_append_basic(&val, DBUS_TYPE_STRING, &gateway);
dbus_message_iter_close_container(&item, &val);
dbus_message_iter_close_container(&array, &item);
}
if (netmask)
{
dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, NULL, &item);
key = "Netmask";
dbus_message_iter_append_basic(&item, DBUS_TYPE_STRING, &key);
dbus_message_iter_open_container(&item, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &val);
dbus_message_iter_append_basic(&val, DBUS_TYPE_STRING, &netmask);
dbus_message_iter_close_container(&item, &val);
dbus_message_iter_close_container(&array, &item);
}
dbus_message_iter_close_container(&iter, &array);
e_dbus_method_call_send(conn, msg, NULL, NULL, NULL, -1, NULL);
dbus_message_unref(msg);
}
void
iface_callback_add(Interface *iface, Interface_Event event, void (*func) (void *data, Interface *iface, Interface_Network *ifnet), void *data)
{
Interface_Callback *cb;
cb = calloc(1, sizeof(Interface_Callback));
if (!cb) return;
cb->event = event;
cb->func = func;
cb->data = data;
iface->callbacks = evas_list_append(iface->callbacks, cb);
}
void
iface_callback_del(Interface *iface, Interface_Event event, void (*func) (void *data, Interface *iface, Interface_Network *ifnet), void *data)
{
Evas_List *l;
for (l = iface->callbacks; l; l = l->next)
{
Interface_Callback *cb;
cb = l->data;
if ((cb->event == event) && (cb->func == func) && (cb->data == data))
{
/* just flag for deletion - cleanup happens later */
cb->delete_me = 1;
return;
}
}
}
void
iface_system_init(E_DBus_Connection *edbus_conn)
{
conn = edbus_conn;
/* init iface system - listen for connman name owner change - if we get it
* connman was sarted or restarted this handles connman starting later
* than the front-end gui */
sigh_name_ownerchanged = e_dbus_signal_handler_add
(conn, "org.freedesktop.DBus", "/org/freedesktop/DBus",
"org.freedesktop.DBus", "NameOwnerChanged",
iface_system_name_ownerchanged, NULL);
/* do an initial list */
iface_system_interfaces_list();
/* FIXME: do we care about connman state? haven't found a use for it yet */
/* FIXME: get state with GetState */
/* FIXME: add signal handler StateChanged */
}
void
iface_system_shutdown(void)
{
Evas_List *l, *tlist = NULL;
for (l = interfaces; l; l = l->next)
tlist = evas_list_append(tlist, l->data);
while (tlist)
{
iface_unref(tlist->data);
tlist = evas_list_remove_list(tlist, tlist);
}
if (sigh_name_ownerchanged)
e_dbus_signal_handler_del(conn, sigh_name_ownerchanged);
sigh_name_ownerchanged = NULL;
if (sigh_interface_added)
e_dbus_signal_handler_del(conn, sigh_interface_added);
sigh_interface_added = NULL;
if (sigh_interface_removed)
e_dbus_signal_handler_del(conn, sigh_interface_removed);
sigh_interface_removed = NULL;
while (callbacks)
{
free(callbacks->data);
callbacks = evas_list_remove_list(callbacks, callbacks);
}
conn = NULL;
}
void
iface_system_callback_add(Interface_Event event, void (*func) (void *data, Interface *iface, Interface_Network *ifnet), void *data)
{
Interface_Callback *cb;
cb = calloc(1, sizeof(Interface_Callback));
if (!cb) return;
cb->event = event;
cb->func = func;
cb->data = data;
callbacks = evas_list_append(callbacks, cb);
}
void
iface_system_callback_del(Interface_Event event, void (*func) (void *data, Interface *iface, Interface_Network *ifnet), void *data)
{
Evas_List *l;
for (l = callbacks; l; l = l->next)
{
Interface_Callback *cb;
cb = l->data;
if ((cb->event == event) && (cb->func == func) && (cb->data == data))
{
/* just flag for deletion - cleanup happens later */
cb->delete_me = 1;
return;
}
}
}
#if 0// TESTING CODE ONLY HERE - EXCERCISE THE API ABOVE
static void
cb_if_del(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF-- %s\n", iface->ifpath);
}
static void
cb_if_ipv4(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF %s\n", iface->ifpath);
printf(" IPV4: [%s][%s][%s][%s]\n",
iface->ipv4.method, iface->ipv4.address,
iface->ipv4.gateway, iface->ipv4.netmask);
}
static void
cb_if_net_sel(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF %s\n", iface->ifpath);
printf(" NET_SEL: [%s] [%s]\n",
iface->network_selection.id, iface->network_selection.pass);
}
static void
cb_if_scan_net_add(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF %s\n", iface->ifpath);
printf(" SCAN NET ADD: [%s] %i \"%s\" %s\n",
ifnet->bssid, ifnet->signal_strength, ifnet->essid, ifnet->security);
}
static void
cb_if_scan_net_del(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF %s\n", iface->ifpath);
printf(" SCAN NET DEL: [%s] %i \"%s\" %s\n",
ifnet->bssid, ifnet->signal_strength, ifnet->essid, ifnet->security);
}
static void
cb_if_scan_net_change(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF %s\n", iface->ifpath);
printf(" SCAN NET CHANGE: [%s] %i \"%s\" %s\n",
ifnet->bssid, ifnet->signal_strength, ifnet->essid, ifnet->security);
}
static void
cb_if_signal(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF %s\n", iface->ifpath);
printf(" SIGNAL: %i\n", iface->signal_strength);
}
static int connect_test = 0;
static int disconnect_test = 0;
static double connect_timeout_test = 5.0;
static char *essid_test = "";
static char *pass_test = "";
// this is testing - every 5 seconds connect then disconnect from the network
static int
delay_up(void *data)
{
Interface *iface = data;
// turn it back on
iface_policy_set(iface, "auto");
iface_network_set(iface, essid_test, pass_test);
return 0;
}
static int
delay_down(void *data)
{
Interface *iface = data;
// turn interface off
iface_policy_set(iface, "off");
// in 5 seconds call delay_up
if (connect_test)
ecore_timer_add(connect_timeout_test, delay_up, iface);
return 0;
}
static void
cb_if_state(void *data, Interface *iface, Interface_Network *ifnet)
{
// .. iface->prop.state:
// scanning
// carrier
// configure
// ready
// unknown
// off
// enabled
// connect
// connected
printf("IF %s\n", iface->ifpath);
printf(" STATE: %s\n", iface->prop.state);
// if we go into a ready state - in 5 seconds, call delay_down
if (disconnect_test)
{
if (!strcmp(iface->prop.state, "ready"))
ecore_timer_add(connect_timeout_test, delay_down, iface);
}
}
static void
cb_if_policy(void *data, Interface *iface, Interface_Network *ifnet)
{
// .. iface->prop.policy:
// unknown
// off
// ignore
// auto
// ask
//
printf("IF %s\n", iface->ifpath);
printf(" POLICY: %s\n", iface->prop.policy);
}
static void
cb_main_if_add(void *data, Interface *iface, Interface_Network *ifnet)
{
printf("IF++ %s\n", iface->ifpath);
// TESTING ...
// add callbacks to events so we know when things happen
iface_callback_add(iface, IFACE_EVENT_DEL, cb_if_del, NULL);
iface_callback_add(iface, IFACE_EVENT_IPV4_CHANGE, cb_if_ipv4, NULL);
iface_callback_add(iface, IFACE_EVENT_NETWORK_SELECTION_CHANGE, cb_if_net_sel, NULL);
iface_callback_add(iface, IFACE_EVENT_SCAN_NETWORK_ADD, cb_if_scan_net_add, NULL);
iface_callback_add(iface, IFACE_EVENT_SCAN_NETWORK_DEL, cb_if_scan_net_del, NULL);
iface_callback_add(iface, IFACE_EVENT_SCAN_NETWORK_CHANGE, cb_if_scan_net_change, NULL);
iface_callback_add(iface, IFACE_EVENT_SIGNAL_CHANGE, cb_if_signal, NULL);
iface_callback_add(iface, IFACE_EVENT_STATE_CHANGE, cb_if_state, NULL);
iface_callback_add(iface, IFACE_EVENT_POLICY_CHANGE, cb_if_policy, NULL);
// .. iface->prop.type:
// unknown
// 80203
// 80211
// wimax
// modem
// bluetooth
//
// if it is 802.11 - try connect
if (essid_test)
{
if ((iface->prop.type) && (!strcmp(iface->prop.type, "80211")))
{
iface_policy_set(iface, "auto");
iface_network_set(iface, essid_test, pass_test);
}
}
}
//////// DRIVE THE TESt SYSTEM ABOVE ////////
int
main(int argc, char **argv)
{
E_DBus_Connection *c;
{
int i;
for (i = 0; i < argc; i++)
{
if (!strcmp(argv[i], "-ct"))
{
connect_test = 1;
}
else if (!strcmp(argv[i], "-dt"))
{
disconnect_test = 1;
}
else if (!strcmp(argv[i], "-e"))
{
essid_test = argv[++i];
}
else if (!strcmp(argv[i], "-p"))
{
pass_test = argv[++i];
}
else if (!strcmp(argv[i], "-t"))
{
connect_timeout_test = atof(argv[++i]);
}
else if (!strcmp(argv[i], "-h"))
{
printf
("Options:\n"
" -ct Enable connection connect test\n"
" -dt Enable connection disconnect test\n"
" -t N Timeout for connect/disconnect test (seconds)\n"
" -e XXX Use Essid XXX\n"
" -p XXX Use passphrase XXX\n"
" -h This help\n"
);
exit(0);
}
}
}
ecore_init();
ecore_string_init();
ecore_app_args_set(argc, (const char **)argv);
e_dbus_init();
evas_init();
c = e_dbus_bus_get(DBUS_BUS_SYSTEM);
if (!c)
{
printf("ERROR: can't connect to system session\n");
exit(-1);
}
// add calback that gets called whenever an interface is added to the system
// or on initial lst of interfaces that are present
iface_system_callback_add(IFACE_EVENT_ADD, cb_main_if_add, NULL);
iface_system_init(c);
ecore_main_loop_begin();
iface_system_shutdown();
e_dbus_connection_close(c);
evas_shutdown();
e_dbus_shutdown();
ecore_string_shutdown();
ecore_shutdown();
return 0;
}
#endif