summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/agent-connman.c173
-rw-r--r--src/agent.c21
-rw-r--r--src/bridge.c2
-rw-r--r--src/config.c146
-rw-r--r--src/connection.c2
-rw-r--r--src/connman.h54
-rw-r--r--src/dbus.c32
-rw-r--r--src/device.c6
-rw-r--r--src/dhcp.c413
-rw-r--r--src/dhcpv6.c197
-rw-r--r--src/dnsproxy.c124
-rw-r--r--src/inet.c63
-rw-r--r--src/inotify.c2
-rw-r--r--src/ipaddress.c84
-rw-r--r--src/ipconfig.c39
-rw-r--r--src/ippool.c2
-rw-r--r--src/machine.c125
-rw-r--r--src/main.c6
-rw-r--r--src/manager.c127
-rw-r--r--src/nat.c2
-rw-r--r--src/net.connman.service.in2
-rw-r--r--src/network.c60
-rw-r--r--src/peer.c913
-rw-r--r--src/peer_service.c429
-rw-r--r--src/service.c417
-rw-r--r--src/session.c2
-rw-r--r--src/shared/netlink.c2
-rw-r--r--src/stats.c2
-rw-r--r--src/tethering.c7
-rw-r--r--src/timeserver.c10
-rw-r--r--src/wispr.c10
31 files changed, 2607 insertions, 867 deletions
diff --git a/src/agent-connman.c b/src/agent-connman.c
index ab538f38..b2049a3d 100644
--- a/src/agent-connman.c
+++ b/src/agent-connman.c
@@ -56,7 +56,12 @@ static bool check_reply_has_dict(DBusMessage *reply)
struct request_input_reply {
struct connman_service *service;
- authentication_cb_t callback;
+ struct connman_peer *peer;
+ union {
+ authentication_cb_t service_callback;
+ peer_wps_cb_t peer_callback;
+ };
+ bool wps_requested;
void *user_data;
};
@@ -151,12 +156,10 @@ static void request_input_passphrase_reply(DBusMessage *reply, void *user_data)
}
done:
- passphrase_reply->callback(passphrase_reply->service, values_received,
- name, name_len,
- identity, passphrase,
- wps, wpspin, error,
- passphrase_reply->user_data);
-
+ passphrase_reply->service_callback(passphrase_reply->service,
+ values_received, name, name_len,
+ identity, passphrase, wps, wpspin,
+ error, passphrase_reply->user_data);
out:
g_free(passphrase_reply);
}
@@ -236,13 +239,21 @@ static void request_input_append_passphrase(DBusMessageIter *iter,
}
}
+struct request_wps_data {
+ bool peer;
+};
+
static void request_input_append_wps(DBusMessageIter *iter, void *user_data)
{
+ struct request_wps_data *wps = user_data;
const char *str = "wpspin";
connman_dbus_dict_append_basic(iter, "Type",
DBUS_TYPE_STRING, &str);
- str = "alternate";
+ if (wps && wps->peer)
+ str = "mandatory";
+ else
+ str = "alternate";
connman_dbus_dict_append_basic(iter, "Requirement",
DBUS_TYPE_STRING, &str);
}
@@ -399,12 +410,10 @@ static void request_input_login_reply(DBusMessage *reply, void *user_data)
}
done:
- username_password_reply->callback(username_password_reply->service,
- values_received, NULL, 0,
- username, password,
- FALSE, NULL, error,
- username_password_reply->user_data);
-
+ username_password_reply->service_callback(
+ username_password_reply->service, values_received,
+ NULL, 0, username, password, FALSE, NULL, error,
+ username_password_reply->user_data);
out:
g_free(username_password_reply);
}
@@ -477,7 +486,7 @@ int __connman_agent_request_passphrase_input(struct connman_service *service,
}
passphrase_reply->service = service;
- passphrase_reply->callback = callback;
+ passphrase_reply->service_callback = callback;
passphrase_reply->user_data = user_data;
err = connman_agent_queue_message(service, message,
@@ -542,7 +551,7 @@ int __connman_agent_request_login_input(struct connman_service *service,
}
username_password_reply->service = service;
- username_password_reply->callback = callback;
+ username_password_reply->service_callback = callback;
username_password_reply->user_data = user_data;
err = connman_agent_queue_message(service, message,
@@ -644,3 +653,135 @@ int __connman_agent_request_browser(struct connman_service *service,
return -EINPROGRESS;
}
+
+int __connman_agent_report_peer_error(struct connman_peer *peer,
+ const char *path, const char *error,
+ report_error_cb_t callback,
+ const char *dbus_sender,
+ void *user_data)
+{
+ return connman_agent_report_error_full(peer, path, "ReportPeerError",
+ error, callback, dbus_sender, user_data);
+}
+
+static void request_peer_authorization_reply(DBusMessage *reply,
+ void *user_data)
+{
+ struct request_input_reply *auth_reply = user_data;
+ DBusMessageIter iter, dict;
+ const char *error = NULL;
+ bool choice_done = false;
+ char *wpspin = NULL;
+ char *key;
+
+ if (!reply)
+ goto out;
+
+ if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
+ error = dbus_message_get_error_name(reply);
+ goto done;
+ }
+
+ if (!check_reply_has_dict(reply))
+ goto done;
+
+ dbus_message_iter_init(reply, &iter);
+ dbus_message_iter_recurse(&iter, &dict);
+ while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, value;
+
+ dbus_message_iter_recurse(&dict, &entry);
+ if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+ break;
+
+ dbus_message_iter_get_basic(&entry, &key);
+
+ if (g_str_equal(key, "WPS")) {
+ choice_done = true;
+
+ dbus_message_iter_next(&entry);
+ if (dbus_message_iter_get_arg_type(&entry)
+ != DBUS_TYPE_VARIANT)
+ break;
+ dbus_message_iter_recurse(&entry, &value);
+ dbus_message_iter_get_basic(&value, &wpspin);
+ break;
+ }
+ dbus_message_iter_next(&dict);
+ }
+
+ if (!auth_reply->wps_requested)
+ choice_done = true;
+
+done:
+ auth_reply->peer_callback(auth_reply->peer, choice_done, wpspin,
+ error, auth_reply->user_data);
+out:
+ g_free(auth_reply);
+}
+
+int __connman_agent_request_peer_authorization(struct connman_peer *peer,
+ peer_wps_cb_t callback,
+ bool wps_requested,
+ const char *dbus_sender,
+ void *user_data)
+{
+ struct request_wps_data wps = { .peer = true };
+ const char *path, *agent_sender, *agent_path;
+ struct request_input_reply *auth_reply;
+ DBusMessageIter dict, iter;
+ DBusMessage *message;
+ void *agent;
+ int err;
+
+ agent = connman_agent_get_info(dbus_sender, &agent_sender,
+ &agent_path);
+ DBG("agent %p peer %p path %s", agent, peer, agent_path);
+
+ if (!peer || !agent || !agent_path || !callback)
+ return -ESRCH;
+
+ message = dbus_message_new_method_call(agent_sender, agent_path,
+ CONNMAN_AGENT_INTERFACE, "RequestPeerAuthorization");
+ if (!message)
+ return -ENOMEM;
+
+ dbus_message_iter_init_append(message, &iter);
+
+ path = __connman_peer_get_path(peer);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+ connman_dbus_dict_open(&iter, &dict);
+
+ if (wps_requested)
+ connman_dbus_dict_append_dict(&dict, "WPS",
+ request_input_append_wps, &wps);
+
+ connman_dbus_dict_close(&iter, &dict);
+
+ auth_reply = g_try_new0(struct request_input_reply, 1);
+ if (!auth_reply) {
+ dbus_message_unref(message);
+ return -ENOMEM;
+ }
+
+ auth_reply->peer = peer;
+ auth_reply->peer_callback = callback;
+ auth_reply->wps_requested = wps_requested;
+ auth_reply->user_data = user_data;
+
+ err = connman_agent_queue_message(peer, message,
+ connman_timeout_input_request(),
+ request_peer_authorization_reply,
+ auth_reply, agent);
+ if (err < 0 && err != -EBUSY) {
+ DBG("error %d sending agent message", err);
+ dbus_message_unref(message);
+ g_free(auth_reply);
+ return err;
+ }
+
+ dbus_message_unref(message);
+
+ return -EINPROGRESS;
+}
diff --git a/src/agent.c b/src/agent.c
index 37cf5247..a3400262 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -350,6 +350,9 @@ static void report_error_reply(DBusMessage *reply, void *user_data)
bool retry = false;
const char *dbus_err;
+ if (!reply)
+ goto out;
+
if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
dbus_err = dbus_message_get_error_name(reply);
if (dbus_err &&
@@ -360,11 +363,12 @@ static void report_error_reply(DBusMessage *reply, void *user_data)
report_error->callback(report_error->user_context, retry,
report_error->user_data);
+out:
g_free(report_error);
}
-int connman_agent_report_error(void *user_context, const char *path,
- const char *error,
+int connman_agent_report_error_full(void *user_context, const char *path,
+ const char *method, const char *error,
report_error_cb_t callback,
const char *dbus_sender, void *user_data)
{
@@ -383,8 +387,7 @@ int connman_agent_report_error(void *user_context, const char *path,
return -ESRCH;
message = dbus_message_new_method_call(agent->owner, agent->path,
- CONNMAN_AGENT_INTERFACE,
- "ReportError");
+ CONNMAN_AGENT_INTERFACE, method);
if (!message)
return -ENOMEM;
@@ -421,6 +424,16 @@ int connman_agent_report_error(void *user_context, const char *path,
return -EINPROGRESS;
}
+int connman_agent_report_error(void *user_context, const char *path,
+ const char *error,
+ report_error_cb_t callback,
+ const char *dbus_sender, void *user_data)
+{
+ return connman_agent_report_error_full(user_context, path,
+ "ReportError", error, callback, dbus_sender,
+ user_data);
+}
+
static gint compare_priority(gconstpointer a, gconstpointer b)
{
const struct connman_agent_driver *driver1 = a;
diff --git a/src/bridge.c b/src/bridge.c
index 034fa139..ba200969 100644
--- a/src/bridge.c
+++ b/src/bridge.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
- * Copyright (C) 2012-2013 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2012-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/config.c b/src/config.c
index 330ae817..93a788a1 100644
--- a/src/config.c
+++ b/src/config.c
@@ -52,6 +52,7 @@ struct connman_config_service {
char *private_key_passphrase_type;
char *phase2;
char *passphrase;
+ enum connman_service_security security;
GSList *service_identifiers;
char *config_ident; /* file prefix */
char *config_entry; /* entry name */
@@ -99,6 +100,7 @@ static bool cleanup = false;
#define SERVICE_KEY_IDENTITY "Identity"
#define SERVICE_KEY_PHASE2 "Phase2"
#define SERVICE_KEY_PASSPHRASE "Passphrase"
+#define SERVICE_KEY_SECURITY "Security"
#define SERVICE_KEY_HIDDEN "Hidden"
#define SERVICE_KEY_IPv4 "IPv4"
@@ -129,6 +131,7 @@ static const char *service_possible_keys[] = {
SERVICE_KEY_IDENTITY,
SERVICE_KEY_PHASE2,
SERVICE_KEY_PASSPHRASE,
+ SERVICE_KEY_SECURITY,
SERVICE_KEY_HIDDEN,
SERVICE_KEY_IPv4,
SERVICE_KEY_IPv6,
@@ -399,7 +402,7 @@ static bool load_service_generic(GKeyFile *keyfile,
char *ptr;
long int value = strtol(mask, &ptr, 10);
- if (ptr != mask && *ptr == '\0' && value <= 32)
+ if (ptr != mask && *ptr == '\0' && value && value <= 32)
prefix_len = value;
addr = 0xffffffff << (32 - prefix_len);
@@ -513,6 +516,7 @@ static bool load_service(GKeyFile *keyfile, const char *group,
struct connman_config_service *service;
const char *ident;
char *str, *hex_ssid;
+ enum connman_service_security security;
bool service_created = false;
/* Strip off "service_" prefix */
@@ -664,6 +668,38 @@ static bool load_service(GKeyFile *keyfile, const char *group,
service->passphrase = str;
}
+ str = __connman_config_get_string(keyfile, group, SERVICE_KEY_SECURITY,
+ NULL);
+ security = __connman_service_string2security(str);
+
+ if (service->eap) {
+
+ if (str && security != CONNMAN_SERVICE_SECURITY_8021X)
+ connman_info("Mismatch between EAP configuration and "
+ "setting %s = %s",
+ SERVICE_KEY_SECURITY, str);
+
+ service->security = CONNMAN_SERVICE_SECURITY_8021X;
+
+ } else if (service->passphrase) {
+
+ if (str) {
+ if (security == CONNMAN_SERVICE_SECURITY_PSK ||
+ security == CONNMAN_SERVICE_SECURITY_WEP) {
+ service->security = security;
+ } else {
+ connman_info("Mismatch with passphrase and "
+ "setting %s = %s",
+ SERVICE_KEY_SECURITY, str);
+
+ service->security =
+ CONNMAN_SERVICE_SECURITY_PSK;
+ }
+
+ } else
+ service->security = CONNMAN_SERVICE_SECURITY_PSK;
+ }
+
service->config_ident = g_strdup(config->ident);
service->config_entry = g_strdup_printf("service_%s", service->ident);
@@ -1062,22 +1098,7 @@ static int try_provision_service(struct connman_config_service *config,
enum connman_service_type type;
const void *ssid;
unsigned int ssid_len;
-
- type = connman_service_get_type(service);
- if (type == CONNMAN_SERVICE_TYPE_WIFI &&
- g_strcmp0(config->type, "wifi") != 0)
- return -ENOENT;
-
- if (type == CONNMAN_SERVICE_TYPE_ETHERNET &&
- g_strcmp0(config->type, "ethernet") != 0)
- return -ENOENT;
-
- if (type == CONNMAN_SERVICE_TYPE_GADGET &&
- g_strcmp0(config->type, "gadget") != 0)
- return -ENOENT;
-
- DBG("service %p ident %s", service,
- __connman_service_get_ident(service));
+ const char *str;
network = __connman_service_get_network(service);
if (!network) {
@@ -1088,6 +1109,54 @@ static int try_provision_service(struct connman_config_service *config,
DBG("network %p ident %s", network,
connman_network_get_identifier(network));
+ type = connman_service_get_type(service);
+
+ switch(type) {
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ if (__connman_service_string2type(config->type) != type)
+ return -ENOENT;
+
+ ssid = connman_network_get_blob(network, "WiFi.SSID",
+ &ssid_len);
+ if (!ssid) {
+ connman_error("Network SSID not set");
+ return -EINVAL;
+ }
+
+ if (!config->ssid || ssid_len != config->ssid_len)
+ return -ENOENT;
+
+ if (memcmp(config->ssid, ssid, ssid_len))
+ return -ENOENT;
+
+ str = connman_network_get_string(network, "WiFi.Security");
+ if (config->security != __connman_service_string2security(str))
+ return -ENOENT;
+
+ break;
+
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+
+ if (__connman_service_string2type(config->type) != type)
+ return -ENOENT;
+
+ break;
+
+ case CONNMAN_SERVICE_TYPE_UNKNOWN:
+ case CONNMAN_SERVICE_TYPE_SYSTEM:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ case CONNMAN_SERVICE_TYPE_GPS:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_P2P:
+
+ return -ENOENT;
+ }
+
+ DBG("service %p ident %s", service,
+ __connman_service_get_ident(service));
+
if (config->mac) {
struct connman_device *device;
const char *device_addr;
@@ -1106,22 +1175,6 @@ static int try_provision_service(struct connman_config_service *config,
return -ENOENT;
}
- if (g_strcmp0(config->type, "wifi") == 0 &&
- type == CONNMAN_SERVICE_TYPE_WIFI) {
- ssid = connman_network_get_blob(network, "WiFi.SSID",
- &ssid_len);
- if (!ssid) {
- connman_error("Network SSID not set");
- return -EINVAL;
- }
-
- if (!config->ssid || ssid_len != config->ssid_len)
- return -ENOENT;
-
- if (memcmp(config->ssid, ssid, ssid_len) != 0)
- return -ENOENT;
- }
-
if (!config->ipv6_address) {
connman_network_set_ipv6_method(network,
CONNMAN_IPCONFIG_METHOD_AUTO);
@@ -1210,9 +1263,6 @@ static int try_provision_service(struct connman_config_service *config,
g_slist_prepend(config->service_identifiers,
g_strdup(service_id));
- if (!config->virtual)
- __connman_service_set_immutable(service, true);
-
__connman_service_set_favorite_delayed(service, true, true);
__connman_service_set_config(service, config->config_ident,
@@ -1240,13 +1290,10 @@ static int try_provision_service(struct connman_config_service *config,
__connman_service_set_timeservers(service,
config->timeservers);
- if (g_strcmp0(config->type, "wifi") == 0 &&
- type == CONNMAN_SERVICE_TYPE_WIFI) {
+ if (type == CONNMAN_SERVICE_TYPE_WIFI) {
provision_service_wifi(config, service, network,
ssid, ssid_len);
- } else
- __connman_service_connect(service,
- CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+ }
__connman_service_mark_dirty();
@@ -1260,8 +1307,21 @@ static int try_provision_service(struct connman_config_service *config,
virtual->vfile = config->virtual_file;
g_timeout_add(0, remove_virtual_config, virtual);
- } else
- __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+
+ return 0;
+ }
+
+ __connman_service_set_immutable(service, true);
+
+ if (type == CONNMAN_SERVICE_TYPE_ETHERNET ||
+ type == CONNMAN_SERVICE_TYPE_GADGET) {
+ __connman_service_connect(service,
+ CONNMAN_SERVICE_CONNECT_REASON_AUTO);
+
+ return 0;
+ }
+
+ __connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
return 0;
}
diff --git a/src/connection.c b/src/connection.c
index e98ccb5c..8fe97258 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
- * Copyright (C) 2011-2013 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2011-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/connman.h b/src/connman.h
index 24db5f8d..da012152 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -88,12 +88,13 @@ int __connman_counter_unregister(const char *owner, const char *path);
int __connman_counter_init(void);
void __connman_counter_cleanup(void);
+#include <connman/agent.h>
+
struct connman_service;
+struct connman_peer;
void __connman_agent_cancel(struct connman_service *service);
-int __connman_service_add_passphrase(struct connman_service *service,
- const gchar *passphrase);
typedef void (* authentication_cb_t) (struct connman_service *service,
bool values_received,
const char *name, int name_len,
@@ -103,6 +104,9 @@ typedef void (* authentication_cb_t) (struct connman_service *service,
typedef void (* browser_authentication_cb_t) (struct connman_service *service,
bool authentication_done,
const char *error, void *user_data);
+typedef void (* peer_wps_cb_t) (struct connman_peer *peer, bool choice_done,
+ const char *wpspin, const char *error,
+ void *user_data);
int __connman_agent_request_passphrase_input(struct connman_service *service,
authentication_cb_t callback,
const char *dbus_sender, void *user_data);
@@ -111,6 +115,16 @@ int __connman_agent_request_login_input(struct connman_service *service,
int __connman_agent_request_browser(struct connman_service *service,
browser_authentication_cb_t callback,
const char *url, void *user_data);
+int __connman_agent_report_peer_error(struct connman_peer *peer,
+ const char *path, const char *error,
+ report_error_cb_t callback,
+ const char *dbus_sender,
+ void *user_data);
+int __connman_agent_request_peer_authorization(struct connman_peer *peer,
+ peer_wps_cb_t callback,
+ bool wps_requested,
+ const char *dbus_sender,
+ void *user_data);
#include <connman/log.h>
@@ -383,7 +397,6 @@ int __connman_ipconfig_address_remove(struct connman_ipconfig *ipconfig);
int __connman_ipconfig_address_unset(struct connman_ipconfig *ipconfig);
int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig);
void __connman_ipconfig_gateway_remove(struct connman_ipconfig *ipconfig);
-unsigned char __connman_ipaddress_netmask_prefix_len(const char *netmask);
int __connman_ipconfig_set_proxy_autoconfig(struct connman_ipconfig *ipconfig,
const char *url);
@@ -400,6 +413,7 @@ int __connman_ipconfig_load(struct connman_ipconfig *ipconfig,
int __connman_ipconfig_save(struct connman_ipconfig *ipconfig,
GKeyFile *keyfile, const char *identifier, const char *prefix);
bool __connman_ipconfig_ipv6_privacy_enabled(struct connman_ipconfig *ipconfig);
+int __connman_ipconfig_ipv6_reset_privacy(struct connman_ipconfig *ipconfig);
int __connman_ipconfig_ipv6_set_privacy(struct connman_ipconfig *ipconfig,
const char *value);
bool __connman_ipconfig_ipv6_is_enabled(struct connman_ipconfig *ipconfig);
@@ -434,10 +448,13 @@ enum __connman_dhcpv6_status {
typedef void (* dhcpv6_cb) (struct connman_network *network,
enum __connman_dhcpv6_status status, gpointer data);
-typedef void (* dhcp_cb) (struct connman_network *network,
+typedef void (* dhcp_cb) (struct connman_ipconfig *ipconfig,
+ struct connman_network *opt_network,
bool success, gpointer data);
-int __connman_dhcp_start(struct connman_network *network, dhcp_cb callback);
-void __connman_dhcp_stop(struct connman_network *network);
+int __connman_dhcp_start(struct connman_ipconfig *ipconfig,
+ struct connman_network *network, dhcp_cb callback,
+ gpointer user_data);
+void __connman_dhcp_stop(struct connman_ipconfig *ipconfig);
int __connman_dhcp_init(void);
void __connman_dhcp_cleanup(void);
int __connman_dhcpv6_init(void);
@@ -711,8 +728,6 @@ void __connman_service_set_hidden_data(struct connman_service *service,
gpointer user_data);
void __connman_service_return_error(struct connman_service *service,
int error, gpointer user_data);
-void __connman_service_reply_dbus_pending(DBusMessage *pending, int error,
- const char *path);
int __connman_service_provision_changed(const char *ident);
void __connman_service_set_config(struct connman_service *service,
@@ -720,6 +735,7 @@ void __connman_service_set_config(struct connman_service *service,
const char *__connman_service_type2string(enum connman_service_type type);
enum connman_service_type __connman_service_string2type(const char *str);
+enum connman_service_security __connman_service_string2security(const char *str);
int __connman_service_nameserver_append(struct connman_service *service,
const char *nameserver, bool is_auto);
@@ -780,6 +796,23 @@ int __connman_peer_init(void);
void __connman_peer_cleanup(void);
void __connman_peer_list_struct(DBusMessageIter *array);
+const char *__connman_peer_get_path(struct connman_peer *peer);
+
+int __connman_peer_service_init(void);
+void __connman_peer_service_cleanup(void);
+
+void __connman_peer_service_set_driver(struct connman_peer_driver *driver);
+int __connman_peer_service_register(const char *owner, DBusMessage *msg,
+ const unsigned char *specification,
+ int specification_length,
+ const unsigned char *query,
+ int query_length, int version,
+ bool master);
+int __connman_peer_service_unregister(const char *owner,
+ const unsigned char *specification,
+ int specification_length,
+ const unsigned char *query,
+ int query_length, int version);
#include <connman/session.h>
@@ -996,3 +1029,8 @@ int __connman_nfacct_disable(struct nfacct_context *ctx,
void *user_data);
void __connman_nfacct_cleanup(void);
+
+#include <connman/machine.h>
+
+int __connman_machine_init(void);
+void __connman_machine_cleanup(void);
diff --git a/src/dbus.c b/src/dbus.c
index 4fa0b362..d80a46ce 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -653,6 +653,38 @@ err:
return err;
}
+void connman_dbus_reply_pending(DBusMessage *pending,
+ int error, const char *path)
+{
+ if (pending) {
+ if (error > 0) {
+ DBusMessage *reply;
+
+ reply = __connman_error_failed(pending, error);
+ if (reply)
+ g_dbus_send_message(connection, reply);
+ } else {
+ const char *sender;
+
+ sender = dbus_message_get_interface(pending);
+ if (!path)
+ path = dbus_message_get_path(pending);
+
+ DBG("sender %s path %s", sender, path);
+
+ if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
+ g_dbus_send_reply(connection, pending,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+ else
+ g_dbus_send_reply(connection, pending,
+ DBUS_TYPE_INVALID);
+ }
+
+ dbus_message_unref(pending);
+ }
+}
+
DBusConnection *connman_dbus_get_connection(void)
{
if (!connection)
diff --git a/src/device.c b/src/device.c
index a97d790e..c0683abd 100644
--- a/src/device.c
+++ b/src/device.c
@@ -185,6 +185,12 @@ int __connman_device_enable(struct connman_device *device)
if (device->powered_pending == PENDING_NONE && device->powered)
return -EALREADY;
+ if (device->index > 0) {
+ err = connman_inet_ifup(device->index);
+ if (err < 0 && err != -EALREADY)
+ return err;
+ }
+
device->powered_pending = PENDING_ENABLE;
err = device->driver->enable(device);
diff --git a/src/dhcp.c b/src/dhcp.c
index 83d7dfb3..505d9f06 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -39,8 +39,10 @@
#define RATE_LIMIT_INTERVAL 60 /* delay between successive attempts */
struct connman_dhcp {
+ struct connman_ipconfig *ipconfig;
struct connman_network *network;
dhcp_cb callback;
+ gpointer user_data;
char **nameservers;
char **timeservers;
@@ -54,7 +56,7 @@ struct connman_dhcp {
char *dhcp_debug_prefix;
};
-static GHashTable *network_table;
+static GHashTable *ipconfig_table;
static bool ipv4ll_running;
static void dhcp_free(struct connman_dhcp *dhcp)
@@ -70,41 +72,36 @@ static void dhcp_free(struct connman_dhcp *dhcp)
g_free(dhcp);
}
-/**
- * dhcp_invalidate: Invalidate an existing DHCP lease
- * @dhcp: pointer to the DHCP lease to invalidate.
- * @callback: flag indicating whether or not to invoke the client callback
- * if present.
- *
- * Invalidates an existing DHCP lease, optionally invoking the client
- * callback. The caller may wish to avoid the client callback invocation
- * when the invocation of that callback might otherwise unnecessarily upset
- * service state due to the IP configuration change implied by this
- * invalidation.
- */
-static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback)
+static void ipv4ll_stop_client(struct connman_dhcp *dhcp)
{
- struct connman_service *service;
- struct connman_ipconfig *ipconfig;
- int i;
+ if (!dhcp->ipv4ll_client)
+ return;
- DBG("dhcp %p callback %u", dhcp, callback);
+ g_dhcp_client_stop(dhcp->ipv4ll_client);
+ g_dhcp_client_unref(dhcp->ipv4ll_client);
+ dhcp->ipv4ll_client = NULL;
+ ipv4ll_running = false;
- if (!dhcp)
- return;
+ g_free(dhcp->ipv4ll_debug_prefix);
+ dhcp->ipv4ll_debug_prefix = NULL;
+}
- service = connman_service_lookup_from_network(dhcp->network);
- if (!service)
- return;
+static bool apply_dhcp_invalidate_on_network(struct connman_dhcp *dhcp)
+{
+ struct connman_service *service;
+ int i;
- ipconfig = __connman_service_get_ip4config(service);
- if (!ipconfig)
- return;
+ if (!dhcp->network)
+ return true;
- __connman_6to4_remove(ipconfig);
+ service = connman_service_lookup_from_network(dhcp->network);
+ if (!service) {
+ connman_error("Can not lookup service");
+ return false;
+ }
__connman_service_set_domainname(service, NULL);
- __connman_service_set_pac(service, NULL);
+ __connman_ipconfig_set_proxy_autoconfig(dhcp->ipconfig, NULL);
if (dhcp->timeservers) {
for (i = 0; dhcp->timeservers[i]; i++) {
@@ -112,7 +109,6 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback)
dhcp->timeservers[i]);
}
}
-
if (dhcp->nameservers) {
for (i = 0; dhcp->nameservers[i]; i++) {
__connman_service_nameserver_remove(service,
@@ -120,25 +116,55 @@ static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback)
}
}
- __connman_ipconfig_set_dhcp_address(ipconfig,
- __connman_ipconfig_get_local(ipconfig));
- DBG("last address %s", __connman_ipconfig_get_dhcp_address(ipconfig));
+ return true;
+}
- __connman_ipconfig_address_remove(ipconfig);
+/**
+ * dhcp_invalidate: Invalidate an existing DHCP lease
+ * @dhcp: pointer to the DHCP lease to invalidate.
+ * @callback: flag indicating whether or not to invoke the client callback
+ * if present.
+ *
+ * Invalidates an existing DHCP lease, optionally invoking the client
+ * callback. The caller may wish to avoid the client callback invocation
+ * when the invocation of that callback might otherwise unnecessarily upset
+ * service state due to the IP configuration change implied by this
+ * invalidation.
+ */
+static void dhcp_invalidate(struct connman_dhcp *dhcp, bool callback)
+{
+ DBG("dhcp %p callback %u", dhcp, callback);
+
+ if (!dhcp)
+ return;
+
+ __connman_6to4_remove(dhcp->ipconfig);
- __connman_ipconfig_set_local(ipconfig, NULL);
- __connman_ipconfig_set_broadcast(ipconfig, NULL);
- __connman_ipconfig_set_gateway(ipconfig, NULL);
- __connman_ipconfig_set_prefixlen(ipconfig, 0);
+ if (!apply_dhcp_invalidate_on_network(dhcp))
+ return;
+
+ __connman_ipconfig_set_dhcp_address(dhcp->ipconfig,
+ __connman_ipconfig_get_local(dhcp->ipconfig));
+ DBG("last address %s",
+ __connman_ipconfig_get_dhcp_address(dhcp->ipconfig));
+
+ __connman_ipconfig_address_remove(dhcp->ipconfig);
+
+ __connman_ipconfig_set_local(dhcp->ipconfig, NULL);
+ __connman_ipconfig_set_broadcast(dhcp->ipconfig, NULL);
+ __connman_ipconfig_set_gateway(dhcp->ipconfig, NULL);
+ __connman_ipconfig_set_prefixlen(dhcp->ipconfig, 0);
if (dhcp->callback && callback)
- dhcp->callback(dhcp->network, false, NULL);
+ dhcp->callback(dhcp->ipconfig, dhcp->network,
+ false, dhcp->user_data);
}
static void dhcp_valid(struct connman_dhcp *dhcp)
{
if (dhcp->callback)
- dhcp->callback(dhcp->network, true, NULL);
+ dhcp->callback(dhcp->ipconfig, dhcp->network,
+ true, dhcp->user_data);
}
static void dhcp_debug(const char *str, void *data)
@@ -146,20 +172,6 @@ static void dhcp_debug(const char *str, void *data)
connman_info("%s: %s", (const char *) data, str);
}
-static void ipv4ll_stop_client(struct connman_dhcp *dhcp)
-{
- if (!dhcp->ipv4ll_client)
- return;
-
- g_dhcp_client_stop(dhcp->ipv4ll_client);
- g_dhcp_client_unref(dhcp->ipv4ll_client);
- dhcp->ipv4ll_client = NULL;
- ipv4ll_running = false;
-
- g_free(dhcp->ipv4ll_debug_prefix);
- dhcp->ipv4ll_debug_prefix = NULL;
-}
-
static void ipv4ll_lost_cb(GDHCPClient *dhcp_client, gpointer user_data);
static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data);
@@ -174,7 +186,7 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp)
if (dhcp->ipv4ll_client)
return -EALREADY;
- index = connman_network_get_index(dhcp->network);
+ index = __connman_ipconfig_get_index(dhcp->ipconfig);
ipv4ll_client = g_dhcp_client_new(G_DHCP_IPV4LL, index, &error);
if (error != G_DHCP_CLIENT_ERROR_NONE)
@@ -189,10 +201,12 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp)
g_dhcp_client_set_id(ipv4ll_client);
- hostname = connman_utsname_get_hostname();
- if (hostname)
- g_dhcp_client_set_send(ipv4ll_client, G_DHCP_HOST_NAME,
- hostname);
+ if (dhcp->network) {
+ hostname = connman_utsname_get_hostname();
+ if (hostname)
+ g_dhcp_client_set_send(ipv4ll_client,
+ G_DHCP_HOST_NAME, hostname);
+ }
g_dhcp_client_register_event(ipv4ll_client,
G_DHCP_CLIENT_EVENT_IPV4LL_LOST, ipv4ll_lost_cb, dhcp);
@@ -216,16 +230,11 @@ static int ipv4ll_start_client(struct connman_dhcp *dhcp)
static gboolean dhcp_retry_cb(gpointer user_data)
{
struct connman_dhcp *dhcp = user_data;
- struct connman_service *service;
- struct connman_ipconfig *ipconfig;
dhcp->timeout = 0;
- service = connman_service_lookup_from_network(dhcp->network);
- ipconfig = __connman_service_get_ip4config(service);
-
g_dhcp_client_start(dhcp->dhcp_client,
- __connman_ipconfig_get_dhcp_address(ipconfig));
+ __connman_ipconfig_get_dhcp_address(dhcp->ipconfig));
return FALSE;
}
@@ -296,78 +305,33 @@ static bool compare_string_arrays(char **array_a, char **array_b)
return true;
}
-static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
+static bool apply_lease_available_on_network(GDHCPClient *dhcp_client,
+ struct connman_dhcp *dhcp)
{
- struct connman_dhcp *dhcp = user_data;
- GList *list, *option = NULL;
- char *address, *netmask = NULL, *gateway = NULL;
- const char *c_address, *c_gateway;
char **nameservers, **timeservers, *pac = NULL;
- int ns_entries;
- struct connman_ipconfig *ipconfig;
struct connman_service *service;
- unsigned char prefixlen, c_prefixlen;
- bool ip_change;
+ GList *list, *option = NULL;
+ int ns_entries;
int i;
- DBG("Lease available");
-
- if (dhcp->ipv4ll_client) {
- ipv4ll_stop_client(dhcp);
- dhcp_invalidate(dhcp, false);
- }
+ if (!dhcp->network)
+ return true;
service = connman_service_lookup_from_network(dhcp->network);
if (!service) {
connman_error("Can not lookup service");
- return;
- }
-
- ipconfig = __connman_service_get_ip4config(service);
- if (!ipconfig) {
- connman_error("Could not lookup ipconfig");
- return;
+ return false;
}
- c_address = __connman_ipconfig_get_local(ipconfig);
- c_gateway = __connman_ipconfig_get_gateway(ipconfig);
- c_prefixlen = __connman_ipconfig_get_prefixlen(ipconfig);
-
- address = g_dhcp_client_get_address(dhcp_client);
-
- __connman_ipconfig_set_dhcp_address(ipconfig, address);
- DBG("last address %s", address);
-
- option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
- if (option)
- netmask = g_strdup(option->data);
-
- option = g_dhcp_client_get_option(dhcp_client, G_DHCP_ROUTER);
+ option = g_dhcp_client_get_option(dhcp_client, 252);
if (option)
- gateway = g_strdup(option->data);
-
- prefixlen = __connman_ipaddress_netmask_prefix_len(netmask);
- if (prefixlen == 255)
- connman_warn("netmask: %s is invalid", netmask);
-
- DBG("c_address %s", c_address);
-
- if (address && c_address && g_strcmp0(address, c_address) != 0)
- ip_change = true;
- else if (gateway && c_gateway && g_strcmp0(gateway, c_gateway) != 0)
- ip_change = true;
- else if (prefixlen != c_prefixlen)
- ip_change = true;
- else if (!c_address || !c_gateway)
- ip_change = true;
- else
- ip_change = false;
+ pac = g_strdup(option->data);
option = g_dhcp_client_get_option(dhcp_client, G_DHCP_DNS_SERVER);
ns_entries = g_list_length(option);
nameservers = g_try_new0(char *, ns_entries + 1);
if (nameservers) {
- for (i = 0, list = option; list; list = list->next, i++)
+ for (i = 0, list = option;list; list = list->next, i++)
nameservers[i] = g_strdup(list->data);
nameservers[ns_entries] = NULL;
}
@@ -389,18 +353,6 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
timeservers[ns_entries] = NULL;
}
- option = g_dhcp_client_get_option(dhcp_client, 252);
- if (option)
- pac = g_strdup(option->data);
-
- __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
-
- if (ip_change) {
- __connman_ipconfig_set_local(ipconfig, address);
- __connman_ipconfig_set_prefixlen(ipconfig, prefixlen);
- __connman_ipconfig_set_gateway(ipconfig, gateway);
- }
-
if (!compare_string_arrays(nameservers, dhcp->nameservers)) {
if (dhcp->nameservers) {
for (i = 0; dhcp->nameservers[i]; i++) {
@@ -412,8 +364,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
dhcp->nameservers = nameservers;
- for (i = 0; dhcp->nameservers &&
- dhcp->nameservers[i]; i++) {
+ for (i = 0; dhcp->nameservers && dhcp->nameservers[i]; i++) {
__connman_service_nameserver_append(service,
dhcp->nameservers[i], false);
}
@@ -432,8 +383,7 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
dhcp->timeservers = timeservers;
- for (i = 0; dhcp->timeservers &&
- dhcp->timeservers[i]; i++) {
+ for (i = 0; dhcp->timeservers && dhcp->timeservers[i]; i++) {
__connman_service_timeserver_append(service,
dhcp->timeservers[i]);
}
@@ -445,14 +395,77 @@ static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
g_free(dhcp->pac);
dhcp->pac = pac;
- __connman_service_set_pac(service, dhcp->pac);
+ __connman_ipconfig_set_proxy_autoconfig(dhcp->ipconfig,
+ dhcp->pac);
+ }
+
+ __connman_6to4_probe(service);
+
+ return true;
+}
+
+static void lease_available_cb(GDHCPClient *dhcp_client, gpointer user_data)
+{
+ struct connman_dhcp *dhcp = user_data;
+ GList *option = NULL;
+ char *address, *netmask = NULL, *gateway = NULL;
+ const char *c_address, *c_gateway;
+ unsigned char prefixlen, c_prefixlen;
+ bool ip_change;
+
+ DBG("Lease available");
+
+ if (dhcp->ipv4ll_client) {
+ ipv4ll_stop_client(dhcp);
+ dhcp_invalidate(dhcp, false);
+ }
+
+ c_address = __connman_ipconfig_get_local(dhcp->ipconfig);
+ c_gateway = __connman_ipconfig_get_gateway(dhcp->ipconfig);
+ c_prefixlen = __connman_ipconfig_get_prefixlen(dhcp->ipconfig);
+
+ address = g_dhcp_client_get_address(dhcp_client);
+
+ __connman_ipconfig_set_dhcp_address(dhcp->ipconfig, address);
+ DBG("last address %s", address);
+
+ option = g_dhcp_client_get_option(dhcp_client, G_DHCP_SUBNET);
+ if (option)
+ netmask = g_strdup(option->data);
+
+ option = g_dhcp_client_get_option(dhcp_client, G_DHCP_ROUTER);
+ if (option)
+ gateway = g_strdup(option->data);
+
+ prefixlen = connman_ipaddress_calc_netmask_len(netmask);
+ if (prefixlen == 255)
+ connman_warn("netmask: %s is invalid", netmask);
+
+ DBG("c_address %s", c_address);
+
+ if (g_strcmp0(address, c_address))
+ ip_change = true;
+ else if (g_strcmp0(gateway, c_gateway))
+ ip_change = true;
+ else if (prefixlen != c_prefixlen)
+ ip_change = true;
+ else
+ ip_change = false;
+
+ __connman_ipconfig_set_method(dhcp->ipconfig,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
+ if (ip_change) {
+ __connman_ipconfig_set_local(dhcp->ipconfig, address);
+ __connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
+ __connman_ipconfig_set_gateway(dhcp->ipconfig, gateway);
}
+ if (!apply_lease_available_on_network(dhcp_client, dhcp))
+ return;
+
if (ip_change)
dhcp_valid(dhcp);
- __connman_6to4_probe(service);
-
g_free(address);
g_free(netmask);
g_free(gateway);
@@ -462,29 +475,20 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data)
{
struct connman_dhcp *dhcp = user_data;
char *address, *netmask;
- struct connman_service *service;
- struct connman_ipconfig *ipconfig;
unsigned char prefixlen;
DBG("IPV4LL available");
- service = connman_service_lookup_from_network(dhcp->network);
- if (!service)
- return;
-
- ipconfig = __connman_service_get_ip4config(service);
- if (!ipconfig)
- return;
-
address = g_dhcp_client_get_address(ipv4ll_client);
netmask = g_dhcp_client_get_netmask(ipv4ll_client);
- prefixlen = __connman_ipaddress_netmask_prefix_len(netmask);
+ prefixlen = connman_ipaddress_calc_netmask_len(netmask);
- __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
- __connman_ipconfig_set_local(ipconfig, address);
- __connman_ipconfig_set_prefixlen(ipconfig, prefixlen);
- __connman_ipconfig_set_gateway(ipconfig, NULL);
+ __connman_ipconfig_set_method(dhcp->ipconfig,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
+ __connman_ipconfig_set_local(dhcp->ipconfig, address);
+ __connman_ipconfig_set_prefixlen(dhcp->ipconfig, prefixlen);
+ __connman_ipconfig_set_gateway(dhcp->ipconfig, NULL);
dhcp_valid(dhcp);
@@ -494,15 +498,13 @@ static void ipv4ll_available_cb(GDHCPClient *ipv4ll_client, gpointer user_data)
static int dhcp_initialize(struct connman_dhcp *dhcp)
{
- struct connman_service *service;
GDHCPClient *dhcp_client;
GDHCPClientError error;
- const char *hostname;
int index;
DBG("dhcp %p", dhcp);
- index = connman_network_get_index(dhcp->network);
+ index = __connman_ipconfig_get_index(dhcp->ipconfig);
dhcp_client = g_dhcp_client_new(G_DHCP_IPV4, index, &error);
if (error != G_DHCP_CLIENT_ERROR_NONE)
@@ -517,22 +519,29 @@ static int dhcp_initialize(struct connman_dhcp *dhcp)
g_dhcp_client_set_id(dhcp_client);
- service = connman_service_lookup_from_network(dhcp->network);
+ if (dhcp->network) {
+ struct connman_service *service;
+ const char *hostname;
- hostname = __connman_service_get_hostname(service);
- if (!hostname)
- hostname = connman_utsname_get_hostname();
+ service = connman_service_lookup_from_network(dhcp->network);
+
+ hostname = __connman_service_get_hostname(service);
+ if (!hostname)
+ hostname = connman_utsname_get_hostname();
- if (hostname)
- g_dhcp_client_set_send(dhcp_client, G_DHCP_HOST_NAME, hostname);
+ if (hostname)
+ g_dhcp_client_set_send(dhcp_client,
+ G_DHCP_HOST_NAME, hostname);
+
+ g_dhcp_client_set_request(dhcp_client, G_DHCP_HOST_NAME);
+ g_dhcp_client_set_request(dhcp_client, G_DHCP_DNS_SERVER);
+ g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME);
+ g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER);
+ g_dhcp_client_set_request(dhcp_client, 252);
+ }
- g_dhcp_client_set_request(dhcp_client, G_DHCP_HOST_NAME);
g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
- g_dhcp_client_set_request(dhcp_client, G_DHCP_DNS_SERVER);
- g_dhcp_client_set_request(dhcp_client, G_DHCP_DOMAIN_NAME);
- g_dhcp_client_set_request(dhcp_client, G_DHCP_NTP_SERVER);
g_dhcp_client_set_request(dhcp_client, G_DHCP_ROUTER);
- g_dhcp_client_set_request(dhcp_client, 252);
g_dhcp_client_register_event(dhcp_client,
G_DHCP_CLIENT_EVENT_LEASE_AVAILABLE,
@@ -553,8 +562,10 @@ static int dhcp_release(struct connman_dhcp *dhcp)
{
DBG("dhcp %p", dhcp);
- if (dhcp->timeout > 0)
+ if (dhcp->timeout > 0) {
g_source_remove(dhcp->timeout);
+ dhcp->timeout = 0;
+ }
if (dhcp->dhcp_client) {
g_dhcp_client_stop(dhcp->dhcp_client);
@@ -571,56 +582,74 @@ static int dhcp_release(struct connman_dhcp *dhcp)
return 0;
}
-int __connman_dhcp_start(struct connman_network *network, dhcp_cb callback)
+int __connman_dhcp_start(struct connman_ipconfig *ipconfig,
+ struct connman_network *network, dhcp_cb callback,
+ gpointer user_data)
{
- struct connman_service *service;
- struct connman_ipconfig *ipconfig;
const char *last_addr = NULL;
struct connman_dhcp *dhcp;
+ int err;
DBG("");
- service = connman_service_lookup_from_network(network);
- if (!service)
- return -EINVAL;
+ if (network) {
+ struct connman_service *service;
- ipconfig = __connman_service_get_ip4config(service);
- if (ipconfig)
- last_addr = __connman_ipconfig_get_dhcp_address(ipconfig);
+ service = connman_service_lookup_from_network(network);
+ if (!service)
+ return -EINVAL;
+ }
+
+ last_addr = __connman_ipconfig_get_dhcp_address(ipconfig);
- dhcp = g_hash_table_lookup(network_table, network);
+ dhcp = g_hash_table_lookup(ipconfig_table, ipconfig);
if (!dhcp) {
dhcp = g_try_new0(struct connman_dhcp, 1);
if (!dhcp)
return -ENOMEM;
- dhcp->network = network;
- connman_network_ref(network);
+ dhcp->ipconfig = ipconfig;
+ __connman_ipconfig_ref(ipconfig);
+
+ if (network) {
+ dhcp->network = network;
+ connman_network_ref(network);
+ }
+
+ err = dhcp_initialize(dhcp);
- g_hash_table_insert(network_table, network, dhcp);
+ if (err < 0) {
+ if (network)
+ connman_network_unref(network);
+ g_free(dhcp);
+ return err;
+ }
- dhcp_initialize(dhcp);
+ g_hash_table_insert(ipconfig_table, ipconfig, dhcp);
}
dhcp->callback = callback;
+ dhcp->user_data = user_data;
return g_dhcp_client_start(dhcp->dhcp_client, last_addr);
}
-void __connman_dhcp_stop(struct connman_network *network)
+void __connman_dhcp_stop(struct connman_ipconfig *ipconfig)
{
struct connman_dhcp *dhcp;
- DBG("network_table %p network %p", network_table, network);
+ DBG("ipconfig_table %p ipconfig %p", ipconfig_table, ipconfig);
- if (!network_table)
+ if (!ipconfig_table)
return;
- dhcp = g_hash_table_lookup(network_table, network);
+ dhcp = g_hash_table_lookup(ipconfig_table, ipconfig);
if (dhcp) {
- g_hash_table_remove(network_table, network);
- connman_network_unref(network);
+ g_hash_table_remove(ipconfig_table, ipconfig);
+ __connman_ipconfig_unref(ipconfig);
+ if (dhcp->network)
+ connman_network_unref(dhcp->network);
dhcp_release(dhcp);
dhcp_invalidate(dhcp, false);
dhcp_free(dhcp);
@@ -631,8 +660,8 @@ int __connman_dhcp_init(void)
{
DBG("");
- network_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
- NULL, NULL);
+ ipconfig_table = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ NULL, NULL);
return 0;
}
@@ -641,6 +670,6 @@ void __connman_dhcp_cleanup(void)
{
DBG("");
- g_hash_table_destroy(network_table);
- network_table = NULL;
+ g_hash_table_destroy(ipconfig_table);
+ ipconfig_table = NULL;
}
diff --git a/src/dhcpv6.c b/src/dhcpv6.c
index 2ede854e..5f8029f1 100644
--- a/src/dhcpv6.c
+++ b/src/dhcpv6.c
@@ -631,6 +631,7 @@ static void set_address(int ifindex, struct connman_ipconfig *ipconfig,
/* Is this prefix part of the subnet we are suppose to use? */
prefix_len = check_ipv6_addr_prefix(prefixes, address);
+ __connman_ipconfig_address_remove(ipconfig);
__connman_ipconfig_set_local(ipconfig, address);
__connman_ipconfig_set_prefixlen(ipconfig, prefix_len);
@@ -804,7 +805,8 @@ static void dad_reply(struct nd_neighbor_advert *reply,
service = __connman_service_lookup_from_index(
data->ifindex);
network = __connman_service_get_network(service);
- data->callback(network, status, NULL);
+ if (network)
+ data->callback(network, status, NULL);
}
}
@@ -1118,6 +1120,7 @@ static void rebind_cb(GDHCPClient *dhcp_client, gpointer user_data)
{
DBG("");
+ g_dhcpv6_client_reset_request(dhcp_client);
g_dhcpv6_client_clear_retransmit(dhcp_client);
re_cb(REQ_REBIND, dhcp_client, user_data);
@@ -1305,6 +1308,7 @@ static void renew_cb(GDHCPClient *dhcp_client, gpointer user_data)
{
DBG("");
+ g_dhcpv6_client_reset_request(dhcp_client);
g_dhcpv6_client_clear_retransmit(dhcp_client);
re_cb(REQ_RENEW, dhcp_client, user_data);
@@ -1398,7 +1402,7 @@ int __connman_dhcpv6_start_renew(struct connman_network *network,
dhcpv6_cb callback)
{
struct connman_dhcpv6 *dhcp;
- uint32_t T1, T2;
+ uint32_t T1, T2, delta;
time_t started, current, expired;
dhcp = g_hash_table_lookup(network_table, network);
@@ -1421,11 +1425,13 @@ int __connman_dhcpv6_start_renew(struct connman_network *network,
/* RFC 3315, 22.4 */
return 0;
- if (T1 == 0)
+ if (T1 == 0) {
/* RFC 3315, 22.4
* Client can choose the timeout.
*/
- T1 = 1800;
+ T1 = (expired - started) / 2;
+ T2 = (expired - started) / 10 * 8;
+ }
dhcp->callback = callback;
@@ -1436,22 +1442,23 @@ int __connman_dhcpv6_start_renew(struct connman_network *network,
if (T2 != 0xffffffff && T2 > 0) {
if ((unsigned)current >= (unsigned)started + T2) {
/* RFC 3315, chapter 18.1.3, start rebind */
- DBG("rebind after %d secs", T2);
+ DBG("start rebind immediately");
- dhcp->timeout = g_timeout_add_seconds(T2, start_rebind,
+ dhcp->timeout = g_timeout_add_seconds(0, start_rebind,
dhcp);
} else if ((unsigned)current < (unsigned)started + T1) {
- DBG("renew after %d secs", T1);
+ delta = started + T1 - current;
+ DBG("renew after %d secs", delta);
- dhcp->timeout = g_timeout_add_seconds(T1, start_renew,
- dhcp);
+ dhcp->timeout = g_timeout_add_seconds(delta,
+ start_renew, dhcp);
} else {
- DBG("rebind after %d secs", T2 - T1);
+ delta = started + T2 - current;
+ DBG("rebind after %d secs", delta);
- dhcp->timeout = g_timeout_add_seconds(T2 - T1,
- start_rebind,
- dhcp);
+ dhcp->timeout = g_timeout_add_seconds(delta,
+ start_rebind, dhcp);
}
}
@@ -1765,145 +1772,11 @@ static gboolean start_solicitation(gpointer user_data)
return FALSE;
}
-static void confirm_cb(GDHCPClient *dhcp_client, gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
- int status = g_dhcpv6_client_get_status(dhcp_client);
-
- DBG("dhcpv6 confirm msg %p status %d", dhcp, status);
-
- clear_timer(dhcp);
-
- g_dhcpv6_client_clear_retransmit(dhcp_client);
-
- /*
- * If confirm fails, start from scratch.
- */
- if (status != 0) {
- g_dhcp_client_unref(dhcp->dhcp_client);
- start_solicitation(dhcp);
- } else {
- do_dad(dhcp_client, dhcp);
- }
-}
-
-static int dhcpv6_confirm(struct connman_dhcpv6 *dhcp)
-{
- GDHCPClient *dhcp_client;
- GDHCPClientError error;
- struct connman_service *service;
- struct connman_ipconfig *ipconfig_ipv6;
- int index, ret;
-
- DBG("dhcp %p", dhcp);
-
- index = connman_network_get_index(dhcp->network);
-
- dhcp_client = g_dhcp_client_new(G_DHCP_IPV6, index, &error);
- if (error != G_DHCP_CLIENT_ERROR_NONE) {
- clear_timer(dhcp);
- return -EINVAL;
- }
-
- if (getenv("CONNMAN_DHCPV6_DEBUG"))
- g_dhcp_client_set_debug(dhcp_client, dhcpv6_debug, "DHCPv6");
-
- service = connman_service_lookup_from_network(dhcp->network);
- if (!service) {
- clear_timer(dhcp);
- g_dhcp_client_unref(dhcp_client);
- return -EINVAL;
- }
-
- ret = set_duid(service, dhcp->network, dhcp_client, index);
- if (ret < 0) {
- clear_timer(dhcp);
- g_dhcp_client_unref(dhcp_client);
- return ret;
- }
-
- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_CLIENTID);
- g_dhcp_client_set_request(dhcp_client, G_DHCPV6_RAPID_COMMIT);
-
- ipconfig_ipv6 = __connman_service_get_ip6config(service);
- dhcp->use_ta = __connman_ipconfig_ipv6_privacy_enabled(ipconfig_ipv6);
-
- g_dhcpv6_client_set_ia(dhcp_client, index,
- dhcp->use_ta ? G_DHCPV6_IA_TA : G_DHCPV6_IA_NA,
- NULL, NULL, TRUE,
- __connman_ipconfig_get_dhcp_address(ipconfig_ipv6));
-
- clear_callbacks(dhcp_client);
-
- g_dhcp_client_register_event(dhcp_client,
- G_DHCP_CLIENT_EVENT_CONFIRM,
- confirm_cb, dhcp);
-
- dhcp->dhcp_client = dhcp_client;
-
- return g_dhcp_client_start(dhcp_client, NULL);
-}
-
-static gboolean timeout_confirm(gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
-
- dhcp->RT = calc_delay(dhcp->RT, CNF_MAX_RT);
-
- DBG("confirm RT timeout %d msec", dhcp->RT);
-
- dhcp->timeout = g_timeout_add(dhcp->RT, timeout_confirm, dhcp);
-
- g_dhcpv6_client_set_retransmit(dhcp->dhcp_client);
-
- g_dhcp_client_start(dhcp->dhcp_client, NULL);
-
- return FALSE;
-}
-
-static gboolean timeout_max_confirm(gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
-
- dhcp->MRD = 0;
-
- clear_timer(dhcp);
-
- DBG("confirm max retransmit duration timeout");
-
- g_dhcpv6_client_clear_retransmit(dhcp->dhcp_client);
-
- if (dhcp->callback)
- dhcp->callback(dhcp->network, CONNMAN_DHCPV6_STATUS_FAIL,
- NULL);
-
- return FALSE;
-}
-
-static gboolean start_confirm(gpointer user_data)
-{
- struct connman_dhcpv6 *dhcp = user_data;
-
- /* Set the confirm timeout, RFC 3315 chapter 14 */
- dhcp->RT = CNF_TIMEOUT * (1 + get_random());
-
- DBG("confirm initial RT timeout %d msec", dhcp->RT);
-
- dhcp->timeout = g_timeout_add(dhcp->RT, timeout_confirm, dhcp);
- dhcp->MRD = g_timeout_add(CNF_MAX_RD, timeout_max_confirm, dhcp);
-
- dhcpv6_confirm(dhcp);
-
- return FALSE;
-}
-
int __connman_dhcpv6_start(struct connman_network *network,
GSList *prefixes, dhcpv6_cb callback)
{
struct connman_service *service;
- struct connman_ipconfig *ipconfig_ipv6;
struct connman_dhcpv6 *dhcp;
- char *last_address;
int delay;
DBG("");
@@ -1936,24 +1809,18 @@ int __connman_dhcpv6_start(struct connman_network *network,
/* Initial timeout, RFC 3315, 17.1.2 */
delay = rand() % 1000;
- ipconfig_ipv6 = __connman_service_get_ip6config(service);
- last_address = __connman_ipconfig_get_dhcp_address(ipconfig_ipv6);
-
- if (prefixes && last_address &&
- check_ipv6_addr_prefix(prefixes,
- last_address) != 128) {
- /*
- * So we are in the same subnet
- * RFC 3315, chapter 18.1.2 Confirm message
- */
- dhcp->timeout = g_timeout_add(delay, start_confirm, dhcp);
- } else {
- /*
- * Start from scratch.
- * RFC 3315, chapter 17.1.2 Solicitation message
- */
- dhcp->timeout = g_timeout_add(delay, start_solicitation, dhcp);
- }
+ /*
+ * Start from scratch.
+ * RFC 3315, chapter 17.1.2 Solicitation message
+ *
+ * Note that we do not send CONFIRM message here as it does
+ * not make much sense because we do not save expiration time
+ * so we cannot really know how long the saved address is valid
+ * anyway. The reply to CONFIRM message does not send
+ * expiration times back to us. Because of this we need to
+ * start using SOLICITATION anyway.
+ */
+ dhcp->timeout = g_timeout_add(delay, start_solicitation, dhcp);
return 0;
}
diff --git a/src/dnsproxy.c b/src/dnsproxy.c
index 7232b987..bdd7fd5c 100644
--- a/src/dnsproxy.c
+++ b/src/dnsproxy.c
@@ -356,8 +356,7 @@ static int dns_name_length(unsigned char *buf)
static void update_cached_ttl(unsigned char *buf, int len, int new_ttl)
{
unsigned char *c;
- uint32_t *i;
- uint16_t *w;
+ uint16_t w;
int l;
/* skip the header */
@@ -387,17 +386,19 @@ static void update_cached_ttl(unsigned char *buf, int len, int new_ttl)
break;
/* now the 4 byte TTL field */
- i = (uint32_t *)c;
- *i = htonl(new_ttl);
+ c[0] = new_ttl >> 24 & 0xff;
+ c[1] = new_ttl >> 16 & 0xff;
+ c[2] = new_ttl >> 8 & 0xff;
+ c[3] = new_ttl & 0xff;
c += 4;
len -= 4;
if (len < 0)
break;
/* now the 2 byte rdlen field */
- w = (uint16_t *)c;
- c += ntohs(*w) + 2;
- len -= ntohs(*w) + 2;
+ w = c[0] << 8 | c[1];
+ c += w + 2;
+ len -= w + 2;
}
}
@@ -435,7 +436,7 @@ static void send_cached_response(int sk, unsigned char *buf, int len,
hdr->id = id;
hdr->qr = 1;
- hdr->rcode = 0;
+ hdr->rcode = ns_r_noerror;
hdr->ancount = htons(answers);
hdr->nscount = 0;
hdr->arcount = 0;
@@ -482,7 +483,7 @@ static void send_response(int sk, unsigned char *buf, int len,
DBG("id 0x%04x qr %d opcode %d", hdr->id, hdr->qr, hdr->opcode);
hdr->qr = 1;
- hdr->rcode = 2;
+ hdr->rcode = ns_r_servfail;
hdr->ancount = 0;
hdr->nscount = 0;
@@ -1344,7 +1345,6 @@ static void cache_refresh(void)
static int reply_query_type(unsigned char *msg, int len)
{
unsigned char *c;
- uint16_t *w;
int l;
int type;
@@ -1358,8 +1358,7 @@ static int reply_query_type(unsigned char *msg, int len)
/* now the query, which is a name and 2 16 bit words */
l = dns_name_length(c) + 1;
c += l;
- w = (uint16_t *) c;
- type = ntohs(*w);
+ type = c[0] << 8 | c[1];
return type;
}
@@ -1401,7 +1400,7 @@ static int cache_update(struct server_data *srv, unsigned char *msg,
DBG("offset %d hdr %p msg %p rcode %d", offset, hdr, msg, hdr->rcode);
/* Continue only if response code is 0 (=ok) */
- if (hdr->rcode != 0)
+ if (hdr->rcode != ns_r_noerror)
return 0;
if (!cache)
@@ -1760,14 +1759,11 @@ static char *uncompress(int16_t field_count, char *start, char *end,
int pos; /* position in compressed string */
char name[NS_MAXLABEL]; /* tmp label */
uint16_t dns_type, dns_class;
+ int comp_pos;
- pos = dn_expand((const u_char *)start, (u_char *)end,
- (u_char *)ptr, name, NS_MAXLABEL);
- if (pos < 0) {
- DBG("uncompress error [%d/%s]", errno,
- strerror(errno));
+ if (!convert_label(start, end, ptr, name, NS_MAXLABEL,
+ &pos, &comp_pos))
goto out;
- }
/*
* Copy the uncompressed resource record, type, class and \0 to
@@ -1775,7 +1771,6 @@ static char *uncompress(int16_t field_count, char *start, char *end,
*/
ulen = strlen(name);
- *uptr++ = ulen;
strncpy(uptr, name, uncomp_len - (uptr - uncompressed));
DBG("pos %d ulen %d left %d name %s", pos, ulen,
@@ -1807,8 +1802,6 @@ static char *uncompress(int16_t field_count, char *start, char *end,
* so we need to uncompress it also when necessary.
*/
if (dns_type == ns_t_cname) {
- int comp_pos;
-
if (!convert_label(start, end, ptr, uptr,
uncomp_len - (uptr - uncompressed),
&pos, &comp_pos))
@@ -1833,7 +1826,6 @@ static char *uncompress(int16_t field_count, char *start, char *end,
ptr += dlen;
} else if (dns_type == ns_t_soa) {
- int comp_pos;
int total_len = 0;
char *len_ptr;
@@ -1884,6 +1876,45 @@ out:
return NULL;
}
+static int strip_domains(char *name, char *answers, int maxlen)
+{
+ uint16_t data_len;
+ int name_len = strlen(name);
+ char *ptr, *start = answers, *end = answers + maxlen;
+
+ while (maxlen > 0) {
+ ptr = strstr(answers, name);
+ if (ptr) {
+ char *domain = ptr + name_len;
+
+ if (*domain) {
+ int domain_len = strlen(domain);
+
+ memmove(answers + name_len,
+ domain + domain_len,
+ end - (domain + domain_len));
+
+ end -= domain_len;
+ maxlen -= domain_len;
+ }
+ }
+
+ answers += strlen(answers) + 1;
+ answers += 2 + 2 + 4; /* skip type, class and ttl fields */
+
+ data_len = answers[0] << 8 | answers[1];
+ answers += 2; /* skip the length field */
+
+ if (answers + data_len > end)
+ return -EINVAL;
+
+ answers += data_len;
+ maxlen -= answers - ptr;
+ }
+
+ return end - start;
+}
+
static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
struct server_data *data)
{
@@ -1911,7 +1942,7 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
req->numresp++;
- if (hdr->rcode == 0 || !req->resp) {
+ if (hdr->rcode == ns_r_noerror || !req->resp) {
unsigned char *new_reply = NULL;
/*
@@ -1979,6 +2010,8 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
*/
if (domain_len > 0) {
int len = host_len + 1;
+ int new_len, fixed_len;
+ char *answers;
/*
* First copy host (without domain name) into
@@ -2001,6 +2034,8 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
*/
ptr += NS_QFIXEDSZ;
uptr += NS_QFIXEDSZ;
+ answers = uptr;
+ fixed_len = answers - uncompressed;
/*
* We then uncompress the result to buffer
@@ -2032,22 +2067,39 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
goto out;
/*
+ * The uncompressed buffer now contains almost
+ * valid response. Final step is to get rid of
+ * the domain name because at least glibc
+ * gethostbyname() implementation does extra
+ * checks and expects to find an answer without
+ * domain name if we asked a query without
+ * domain part. Note that glibc getaddrinfo()
+ * works differently and accepts FQDN in answer
+ */
+ new_len = strip_domains(uncompressed, answers,
+ uptr - answers);
+ if (new_len < 0) {
+ DBG("Corrupted packet");
+ return -EINVAL;
+ }
+
+ /*
* Because we have now uncompressed the answers
- * we must create a bigger buffer to hold all
- * that data.
+ * we might have to create a bigger buffer to
+ * hold all that data.
*/
- new_reply = g_try_malloc(header_len +
- uptr - uncompressed);
+ reply_len = header_len + new_len + fixed_len;
+
+ new_reply = g_try_malloc(reply_len);
if (!new_reply)
return -ENOMEM;
memcpy(new_reply, reply, header_len);
memcpy(new_reply + header_len, uncompressed,
- uptr - uncompressed);
+ new_len + fixed_len);
reply = new_reply;
- reply_len = header_len + uptr - uncompressed;
}
}
@@ -2068,8 +2120,13 @@ static int forward_dns_reply(unsigned char *reply, int reply_len, int protocol,
}
out:
- if (hdr->rcode > 0 && req->numresp < req->numserv)
- return -EINVAL;
+ if (req->numresp < req->numserv) {
+ if (hdr->rcode > ns_r_noerror) {
+ return -EINVAL;
+ } else if (hdr->ancount == 0 && req->append_domain) {
+ return -EINVAL;
+ }
+ }
request_list = g_slist_remove(request_list, req);
@@ -2147,7 +2204,8 @@ static void destroy_server(struct server_data *server)
* without any good reason. The small delay allows the new RDNSS to
* create a new DNS server instance and the refcount does not go to 0.
*/
- g_timeout_add_seconds(3, try_remove_cache, NULL);
+ if (cache)
+ g_timeout_add_seconds(3, try_remove_cache, NULL);
g_free(server);
}
diff --git a/src/inet.c b/src/inet.c
index 61116297..cd220ffc 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -240,36 +240,6 @@ char *connman_inet_ifname(int index)
return g_strdup(ifr.ifr_name);
}
-short int connman_inet_ifflags(int index)
-{
- struct ifreq ifr;
- int sk, err;
-
- sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (sk < 0)
- return -errno;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = index;
-
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
- err = -errno;
- goto done;
- }
-
- if (ioctl(sk, SIOCGIFFLAGS, &ifr) < 0) {
- err = -errno;
- goto done;
- }
-
- err = ifr.ifr_flags;
-
-done:
- close(sk);
-
- return err;
-}
-
int connman_inet_ifup(int index)
{
struct ifreq ifr;
@@ -360,36 +330,6 @@ done:
return err;
}
-bool connman_inet_is_cfg80211(int index)
-{
- bool result = false;
- char phy80211_path[PATH_MAX];
- struct stat st;
- struct ifreq ifr;
- int sk;
-
- sk = socket(PF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (sk < 0)
- return false;
-
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_ifindex = index;
-
- if (ioctl(sk, SIOCGIFNAME, &ifr) < 0)
- goto done;
-
- snprintf(phy80211_path, PATH_MAX,
- "/sys/class/net/%s/phy80211", ifr.ifr_name);
-
- if (stat(phy80211_path, &st) == 0 && (st.st_mode & S_IFDIR))
- result = true;
-
-done:
- close(sk);
-
- return result;
-}
-
struct in6_ifreq {
struct in6_addr ifr6_addr;
__u32 ifr6_prefixlen;
@@ -480,7 +420,8 @@ int connman_inet_clear_address(int index, struct connman_ipaddress *ipaddress)
broadcast = ipaddress->broadcast;
peer = ipaddress->peer;
- DBG("index %d address %s prefix_len %d", index, address, prefix_len);
+ DBG("index %d address %s prefix_len %d peer %s broadcast %s", index,
+ address, prefix_len, peer, broadcast);
if (!address)
return -EINVAL;
diff --git a/src/inotify.c b/src/inotify.c
index 72ba6f68..1ab3807c 100644
--- a/src/inotify.c
+++ b/src/inotify.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
- * Copyright (C) 2012-2013 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2012-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/ipaddress.c b/src/ipaddress.c
index 57f9435d..d63d95c3 100644
--- a/src/ipaddress.c
+++ b/src/ipaddress.c
@@ -33,6 +33,29 @@
#include "connman.h"
+unsigned char connman_ipaddress_calc_netmask_len(const char *netmask)
+{
+ unsigned char bits;
+ in_addr_t mask;
+ in_addr_t host;
+
+ if (!netmask)
+ return 32;
+
+ mask = inet_network(netmask);
+ host = ~mask;
+
+ /* a valid netmask must be 2^n - 1 */
+ if ((host & (host + 1)) != 0)
+ return -1;
+
+ bits = 0;
+ for (; mask; mask <<= 1)
+ ++bits;
+
+ return bits;
+}
+
struct connman_ipaddress *connman_ipaddress_alloc(int family)
{
struct connman_ipaddress *ipaddress;
@@ -63,29 +86,6 @@ void connman_ipaddress_free(struct connman_ipaddress *ipaddress)
g_free(ipaddress);
}
-unsigned char __connman_ipaddress_netmask_prefix_len(const char *netmask)
-{
- unsigned char bits;
- in_addr_t mask;
- in_addr_t host;
-
- if (!netmask)
- return 32;
-
- mask = inet_network(netmask);
- host = ~mask;
-
- /* a valid netmask must be 2^n - 1 */
- if ((host & (host + 1)) != 0)
- return -1;
-
- bits = 0;
- for (; mask; mask <<= 1)
- ++bits;
-
- return bits;
-}
-
static bool check_ipv6_address(const char *address)
{
unsigned char buf[sizeof(struct in6_addr)];
@@ -128,6 +128,19 @@ int connman_ipaddress_set_ipv6(struct connman_ipaddress *ipaddress,
return 0;
}
+int connman_ipaddress_get_ip(struct connman_ipaddress *ipaddress,
+ const char **address,
+ unsigned char *netmask_prefix_length)
+{
+ if (!ipaddress)
+ return -EINVAL;
+
+ *netmask_prefix_length = ipaddress->prefixlen;
+ *address = ipaddress->local;
+
+ return 0;
+}
+
int connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
const char *address, const char *netmask, const char *gateway)
{
@@ -136,7 +149,7 @@ int connman_ipaddress_set_ipv4(struct connman_ipaddress *ipaddress,
ipaddress->family = AF_INET;
- ipaddress->prefixlen = __connman_ipaddress_netmask_prefix_len(netmask);
+ ipaddress->prefixlen = connman_ipaddress_calc_netmask_len(netmask);
g_free(ipaddress->local);
ipaddress->local = g_strdup(address);
@@ -179,8 +192,7 @@ void connman_ipaddress_clear(struct connman_ipaddress *ipaddress)
/*
* Note that this copy function only copies the actual address and
- * prefixlen. If you need full copy of ipaddress struct, then you need
- * to create a new function that does that.
+ * prefixlen. Use the other copy function to copy the whole struct.
*/
void connman_ipaddress_copy_address(struct connman_ipaddress *ipaddress,
struct connman_ipaddress *source)
@@ -194,3 +206,23 @@ void connman_ipaddress_copy_address(struct connman_ipaddress *ipaddress,
g_free(ipaddress->local);
ipaddress->local = g_strdup(source->local);
}
+
+struct connman_ipaddress *
+connman_ipaddress_copy(struct connman_ipaddress *ipaddress)
+{
+ struct connman_ipaddress *copy;
+
+ if (!ipaddress)
+ return NULL;
+
+ copy = g_new0(struct connman_ipaddress, 1);
+
+ copy->family = ipaddress->family;
+ copy->prefixlen = ipaddress->prefixlen;
+ copy->local = g_strdup(ipaddress->local);
+ copy->peer = g_strdup(ipaddress->peer);
+ copy->broadcast = g_strdup(ipaddress->broadcast);
+ copy->gateway = g_strdup(ipaddress->gateway);
+
+ return copy;
+}
diff --git a/src/ipconfig.c b/src/ipconfig.c
index b23df160..ae70745f 100644
--- a/src/ipconfig.c
+++ b/src/ipconfig.c
@@ -1090,8 +1090,6 @@ int __connman_ipconfig_gateway_add(struct connman_ipconfig *ipconfig)
if (!service)
return -EINVAL;
- __connman_connection_gateway_remove(service, ipconfig->type);
-
DBG("type %d gw %s peer %s", ipconfig->type,
ipconfig->address->gateway, ipconfig->address->peer);
@@ -1703,10 +1701,6 @@ int __connman_ipconfig_disable(struct connman_ipconfig *ipconfig)
if (ipdevice->config_ipv6 == ipconfig) {
ipconfig_list = g_list_remove(ipconfig_list, ipconfig);
- if (ipdevice->config_ipv6->method ==
- CONNMAN_IPCONFIG_METHOD_AUTO)
- disable_ipv6(ipdevice->config_ipv6);
-
connman_ipaddress_clear(ipdevice->config_ipv6->system);
__connman_ipconfig_unref(ipdevice->config_ipv6);
ipdevice->config_ipv6 = NULL;
@@ -1776,6 +1770,25 @@ static int string2privacy(const char *privacy)
return 0;
}
+int __connman_ipconfig_ipv6_reset_privacy(struct connman_ipconfig *ipconfig)
+{
+ struct connman_ipdevice *ipdevice;
+ int err;
+
+ if (!ipconfig)
+ return -EINVAL;
+
+ ipdevice = g_hash_table_lookup(ipdevice_hash,
+ GINT_TO_POINTER(ipconfig->index));
+ if (!ipdevice)
+ return -ENODEV;
+
+ err = __connman_ipconfig_ipv6_set_privacy(ipconfig, privacy2string(
+ ipdevice->ipv6_privacy));
+
+ return err;
+}
+
int __connman_ipconfig_ipv6_set_privacy(struct connman_ipconfig *ipconfig,
const char *value)
{
@@ -2093,8 +2106,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
case CONNMAN_IPCONFIG_METHOD_OFF:
ipconfig->method = method;
- if (ipconfig->type == CONNMAN_IPCONFIG_TYPE_IPV6)
- disable_ipv6(ipconfig);
+
break;
case CONNMAN_IPCONFIG_METHOD_AUTO:
@@ -2104,7 +2116,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
ipconfig->method = method;
if (privacy_string)
ipconfig->ipv6_privacy_config = privacy;
- enable_ipv6(ipconfig);
+
break;
case CONNMAN_IPCONFIG_METHOD_MANUAL:
@@ -2139,6 +2151,7 @@ int __connman_ipconfig_set_config(struct connman_ipconfig *ipconfig,
return connman_ipaddress_set_ipv6(
ipconfig->address, address,
prefix_length, gateway);
+
break;
case CONNMAN_IPCONFIG_METHOD_DHCP:
@@ -2168,9 +2181,11 @@ void __connman_ipconfig_append_ethernet(struct connman_ipconfig *ipconfig,
if (ipconfig->index >= 0) {
char *ifname = connman_inet_ifname(ipconfig->index);
- connman_dbus_dict_append_basic(iter, "Interface",
- DBUS_TYPE_STRING, &ifname);
- g_free(ifname);
+ if (ifname) {
+ connman_dbus_dict_append_basic(iter, "Interface",
+ DBUS_TYPE_STRING, &ifname);
+ g_free(ifname);
+ }
}
if (ipdevice->address)
diff --git a/src/ippool.c b/src/ippool.c
index 558e9662..bb8568d9 100644
--- a/src/ippool.c
+++ b/src/ippool.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2007-2013 Intel Corporation. All rights reserved.
- * Copyright (C) 2012-2013 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2012-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/machine.c b/src/machine.c
new file mode 100644
index 00000000..14ea3667
--- /dev/null
+++ b/src/machine.c
@@ -0,0 +1,125 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2014 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 <errno.h>
+#include <gdbus.h>
+
+#include "connman.h"
+
+#define DEFAULT_MACHINE_TYPE "laptop"
+
+#define HOSTNAMED_SERVICE "org.freedesktop.hostname1"
+#define HOSTNAMED_INTERFACE HOSTNAMED_SERVICE
+#define HOSTNAMED_PATH "/org/freedesktop/hostname1"
+
+static GDBusClient *hostnamed_client = NULL;
+static GDBusProxy *hostnamed_proxy = NULL;
+static char *machine_type = NULL;
+
+const char *connman_machine_get_type(void)
+{
+ if (machine_type)
+ return machine_type;
+
+ return DEFAULT_MACHINE_TYPE;
+}
+
+static void machine_property_changed(GDBusProxy *proxy, const char *name,
+ DBusMessageIter *iter, void *user_data)
+{
+ DBG("Property %s", name);
+
+ if (g_str_equal(name, "Chassis")) {
+ const char *str;
+
+ if (!iter) {
+ g_dbus_proxy_refresh_property(proxy, name);
+ return;
+ }
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+ return;
+
+ dbus_message_iter_get_basic(iter, &str);
+ g_free(machine_type);
+ machine_type = g_strdup(str);
+
+ DBG("Machine type set to %s", machine_type);
+ }
+}
+
+int __connman_machine_init(void)
+{
+ DBusConnection *connection;
+ int err = -EIO;
+
+ DBG("");
+
+ connection = connman_dbus_get_connection();
+
+ hostnamed_client = g_dbus_client_new(connection, HOSTNAMED_SERVICE,
+ HOSTNAMED_PATH);
+ if (!hostnamed_client)
+ goto error;
+
+ hostnamed_proxy = g_dbus_proxy_new(hostnamed_client, HOSTNAMED_PATH,
+ HOSTNAMED_INTERFACE);
+ if (!hostnamed_proxy)
+ goto error;
+
+ g_dbus_proxy_set_property_watch(hostnamed_proxy,
+ machine_property_changed, NULL);
+
+ dbus_connection_unref(connection);
+
+ return 0;
+error:
+ if (hostnamed_client) {
+ g_dbus_client_unref(hostnamed_client);
+ hostnamed_client = NULL;
+ }
+
+ dbus_connection_unref(connection);
+
+ return err;
+}
+
+void __connman_machine_cleanup(void)
+{
+ DBG("");
+
+ if (hostnamed_proxy) {
+ g_dbus_proxy_unref(hostnamed_proxy);
+ hostnamed_proxy = NULL;
+ }
+
+ if (hostnamed_client) {
+ g_dbus_client_unref(hostnamed_client);
+ hostnamed_client = NULL;
+ }
+
+ g_free(machine_type);
+ machine_type = NULL;
+}
diff --git a/src/main.c b/src/main.c
index 4f635de5..21d1e06f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -644,6 +644,7 @@ int main(int argc, char *argv[])
__connman_notifier_init();
__connman_agent_init();
__connman_service_init();
+ __connman_peer_service_init();
__connman_peer_init();
__connman_provider_init();
__connman_network_init();
@@ -678,6 +679,7 @@ int main(int argc, char *argv[])
__connman_wpad_init();
__connman_wispr_init();
__connman_rfkill_init();
+ __connman_machine_init();
g_free(option_config);
g_free(option_device);
@@ -689,6 +691,7 @@ int main(int argc, char *argv[])
g_source_remove(signal);
+ __connman_machine_cleanup();
__connman_rfkill_cleanup();
__connman_wispr_cleanup();
__connman_wpad_cleanup();
@@ -713,12 +716,13 @@ int main(int argc, char *argv[])
__connman_nat_cleanup();
__connman_firewall_cleanup();
__connman_iptables_cleanup();
+ __connman_peer_service_cleanup();
+ __connman_peer_cleanup();
__connman_ippool_cleanup();
__connman_device_cleanup();
__connman_network_cleanup();
__connman_dhcp_cleanup();
__connman_service_cleanup();
- __connman_peer_cleanup();
__connman_agent_cleanup();
__connman_ipconfig_cleanup();
__connman_notifier_cleanup();
diff --git a/src/manager.c b/src/manager.c
index b31ab4c7..d15ce203 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -380,6 +380,126 @@ static DBusMessage *release_private_network(DBusConnection *conn,
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
+static int parse_peers_service_specs(DBusMessageIter *array,
+ const unsigned char **spec, int *spec_len,
+ const unsigned char **query, int *query_len,
+ int *version)
+{
+ *spec = *query = NULL;
+ *spec_len = *query_len = *version = 0;
+
+ while (dbus_message_iter_get_arg_type(array) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter entry, inter, value;
+ const char *key;
+
+ dbus_message_iter_recurse(array, &entry);
+ dbus_message_iter_get_basic(&entry, &key);
+
+ dbus_message_iter_next(&entry);
+
+ dbus_message_iter_recurse(&entry, &inter);
+
+ if (!g_strcmp0(key, "BonjourResponse")) {
+ dbus_message_iter_recurse(&inter, &value);
+ dbus_message_iter_get_fixed_array(&value,
+ spec, spec_len);
+ } else if (!g_strcmp0(key, "BonjourQuery")) {
+ dbus_message_iter_recurse(&inter, &value);
+ dbus_message_iter_get_fixed_array(&value,
+ query, query_len);
+ } else if (!g_strcmp0(key, "UpnpService")) {
+ dbus_message_iter_get_basic(&inter, spec);
+ *spec_len = strlen((const char *)*spec)+1;
+ } else if (!g_strcmp0(key, "UpnpVersion")) {
+ dbus_message_iter_get_basic(&inter, version);
+ } else if (!g_strcmp0(key, "WiFiDisplayIEs")) {
+ if (*spec || *query)
+ return -EINVAL;
+
+ dbus_message_iter_recurse(&inter, &value);
+ dbus_message_iter_get_fixed_array(&value,
+ spec, spec_len);
+ } else
+ return -EINVAL;
+
+ dbus_message_iter_next(array);
+ }
+
+ if ((*query && !*spec && !*version) ||
+ (!*spec && !*query) || (!*spec && *version))
+ return -EINVAL;
+
+ return 0;
+}
+
+static DBusMessage *register_peer_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const unsigned char *spec, *query;
+ DBusMessageIter iter, array;
+ int spec_len, query_len;
+ dbus_bool_t master;
+ const char *owner;
+ int version;
+ int ret;
+
+ DBG("");
+
+ owner = dbus_message_get_sender(msg);
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_recurse(&iter, &array);
+
+ ret = parse_peers_service_specs(&array, &spec, &spec_len,
+ &query, &query_len, &version);
+ if (ret)
+ goto error;
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_get_basic(&iter, &master);
+
+ ret = __connman_peer_service_register(owner, msg, spec, spec_len,
+ query, query_len, version,master);
+ if (!ret)
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+ if (ret == -EINPROGRESS)
+ return NULL;
+error:
+ return __connman_error_failed(msg, -ret);
+}
+
+static DBusMessage *unregister_peer_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const unsigned char *spec, *query;
+ DBusMessageIter iter, array;
+ int spec_len, query_len;
+ const char *owner;
+ int version;
+ int ret;
+
+ DBG("");
+
+ owner = dbus_message_get_sender(msg);
+
+ dbus_message_iter_init(msg, &iter);
+ dbus_message_iter_recurse(&iter, &array);
+
+ ret = parse_peers_service_specs(&array, &spec, &spec_len,
+ &query, &query_len, &version);
+ if (ret)
+ goto error;
+
+ ret = __connman_peer_service_unregister(owner, spec, spec_len,
+ query, query_len, version);
+ if (!ret)
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+error:
+ return __connman_error_failed(msg, -ret);
+
+}
+
static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
@@ -432,6 +552,13 @@ static const GDBusMethodTable manager_methods[] = {
{ GDBUS_METHOD("ReleasePrivateNetwork",
GDBUS_ARGS({ "path", "o" }), NULL,
release_private_network) },
+ { GDBUS_ASYNC_METHOD("RegisterPeerService",
+ GDBUS_ARGS({ "specification", "a{sv}" },
+ { "master", "b" }), NULL,
+ register_peer_service) },
+ { GDBUS_METHOD("UnregisterPeerService",
+ GDBUS_ARGS({ "specification", "a{sv}" }), NULL,
+ unregister_peer_service) },
{ },
};
diff --git a/src/nat.c b/src/nat.c
index 4d235504..063f0851 100644
--- a/src/nat.c
+++ b/src/nat.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2007-2012 Intel Corporation. All rights reserved.
- * Copyright (C) 2012 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2012-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/net.connman.service.in b/src/net.connman.service.in
index 0bb1e8b9..e76969bc 100644
--- a/src/net.connman.service.in
+++ b/src/net.connman.service.in
@@ -1,5 +1,5 @@
[D-BUS Service]
Name=net.connman
-Exec=@prefix@/sbin/connman -n
+Exec=@prefix@/sbin/connmand -n
User=root
SystemdService=connman.service
diff --git a/src/network.c b/src/network.c
index 160bd061..b388995f 100644
--- a/src/network.c
+++ b/src/network.c
@@ -202,7 +202,8 @@ static void dhcp_failure(struct connman_network *network)
__connman_ipconfig_gateway_remove(ipconfig_ipv4);
}
-static void dhcp_callback(struct connman_network *network,
+static void dhcp_callback(struct connman_ipconfig *ipconfig,
+ struct connman_network *network,
bool success, gpointer data)
{
if (success)
@@ -285,13 +286,19 @@ err:
static int set_connected_dhcp(struct connman_network *network)
{
+ struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
int err;
DBG("network %p", network);
set_configuration(network, CONNMAN_IPCONFIG_TYPE_IPV4);
- err = __connman_dhcp_start(network, dhcp_callback);
+ service = connman_service_lookup_from_network(network);
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
+
+ err = __connman_dhcp_start(ipconfig_ipv4, network,
+ dhcp_callback, NULL);
if (err < 0) {
connman_error("Can not request DHCP lease");
return err;
@@ -457,6 +464,7 @@ static void check_dhcpv6(struct nd_router_advert *reply,
unsigned int length, void *user_data)
{
struct connman_network *network = user_data;
+ struct connman_service *service;
GSList *prefixes;
DBG("reply %p", reply);
@@ -492,6 +500,23 @@ static void check_dhcpv6(struct nd_router_advert *reply,
prefixes = __connman_inet_ipv6_get_prefixes(reply, length);
/*
+ * If IPv6 config is missing from service, then create it.
+ * The ipconfig might be missing if we got a rtnl message
+ * that disabled IPv6 config and thus removed it. This
+ * can happen if we are switching from one service to
+ * another in the same interface. The only way to get IPv6
+ * config back is to re-create it here.
+ */
+ service = connman_service_lookup_from_network(network);
+ if (service) {
+ connman_service_create_ip6config(service, network->index);
+
+ __connman_service_ipconfig_indicate_state(service,
+ CONNMAN_SERVICE_STATE_CONFIGURATION,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
+ }
+
+ /*
* We do stateful/stateless DHCPv6 if router advertisement says so.
*/
if (reply->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
@@ -587,6 +612,8 @@ static void autoconf_ipv6_set(struct connman_network *network)
if (!ipconfig)
return;
+ __connman_ipconfig_address_remove(ipconfig);
+
index = __connman_ipconfig_get_index(ipconfig);
connman_network_ref(network);
@@ -717,7 +744,7 @@ static void set_disconnected(struct connman_network *network)
case CONNMAN_IPCONFIG_METHOD_MANUAL:
break;
case CONNMAN_IPCONFIG_METHOD_DHCP:
- __connman_dhcp_stop(network);
+ __connman_dhcp_stop(ipconfig_ipv4);
break;
}
}
@@ -1385,22 +1412,6 @@ void connman_network_set_error(struct connman_network *network,
network_change(network);
}
-void connman_network_clear_error(struct connman_network *network)
-{
- struct connman_service *service;
-
- DBG("network %p", network);
-
- if (!network)
- return;
-
- if (network->connecting || network->associating)
- return;
-
- service = connman_service_lookup_from_network(network);
- __connman_service_clear_error(service);
-}
-
/**
* connman_network_set_connected:
* @network: network structure
@@ -1469,7 +1480,7 @@ void connman_network_clear_hidden(void *user_data)
* error to the caller telling that we could not find
* any network that we could connect to.
*/
- __connman_service_reply_dbus_pending(user_data, EIO, NULL);
+ connman_dbus_reply_pending(user_data, EIO, NULL);
}
int connman_network_connect_hidden(struct connman_network *network,
@@ -1489,7 +1500,7 @@ int connman_network_connect_hidden(struct connman_network *network,
__connman_service_set_agent_identity(service, identity);
if (passphrase)
- err = __connman_service_add_passphrase(service, passphrase);
+ err = __connman_service_set_passphrase(service, passphrase);
if (err == -ENOKEY) {
__connman_service_indicate_error(service,
@@ -1607,6 +1618,7 @@ int __connman_network_clear_ipconfig(struct connman_network *network,
struct connman_ipconfig *ipconfig)
{
struct connman_service *service;
+ struct connman_ipconfig *ipconfig_ipv4;
enum connman_ipconfig_method method;
enum connman_ipconfig_type type;
@@ -1614,6 +1626,7 @@ int __connman_network_clear_ipconfig(struct connman_network *network,
if (!service)
return -EINVAL;
+ ipconfig_ipv4 = __connman_service_get_ip4config(service);
method = __connman_ipconfig_get_method(ipconfig);
type = __connman_ipconfig_get_config_type(ipconfig);
@@ -1629,7 +1642,7 @@ int __connman_network_clear_ipconfig(struct connman_network *network,
__connman_ipconfig_address_remove(ipconfig);
break;
case CONNMAN_IPCONFIG_METHOD_DHCP:
- __connman_dhcp_stop(network);
+ __connman_dhcp_stop(ipconfig_ipv4);
break;
}
@@ -1691,7 +1704,8 @@ int __connman_network_set_ipconfig(struct connman_network *network,
case CONNMAN_IPCONFIG_METHOD_MANUAL:
return manual_ipv4_set(network, ipconfig_ipv4);
case CONNMAN_IPCONFIG_METHOD_DHCP:
- return __connman_dhcp_start(network, dhcp_callback);
+ return __connman_dhcp_start(ipconfig_ipv4,
+ network, dhcp_callback, NULL);
}
}
diff --git a/src/peer.c b/src/peer.c
index ce3b582e..caff70c8 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -24,7 +24,11 @@
#endif
#include <errno.h>
+#include <ctype.h>
#include <gdbus.h>
+#include <gdhcp/gdhcp.h>
+
+#include <connman/agent.h>
#include "connman.h"
@@ -32,21 +36,304 @@ static DBusConnection *connection = NULL;
static GHashTable *peers_table = NULL;
+static struct connman_peer_driver *peer_driver;
+
+struct _peers_notify {
+ int id;
+ GHashTable *add;
+ GHashTable *remove;
+} *peers_notify;
+
+struct _peer_service {
+ enum connman_peer_service_type type;
+ unsigned char *data;
+ int length;
+};
+
struct connman_peer {
+ int refcount;
+ struct connman_device *device;
+ struct connman_device *sub_device;
char *identifier;
char *name;
char *path;
+ enum connman_peer_state state;
+ struct connman_ipconfig *ipconfig;
+ DBusMessage *pending;
+ bool registered;
+ bool connection_master;
+ struct connman_ippool *ip_pool;
+ GDHCPServer *dhcp_server;
+ GSList *services;
};
+static void stop_dhcp_server(struct connman_peer *peer)
+{
+ DBG("");
+
+ if (peer->dhcp_server)
+ g_dhcp_server_unref(peer->dhcp_server);
+
+ peer->dhcp_server = NULL;
+
+ if (peer->ip_pool)
+ __connman_ippool_unref(peer->ip_pool);
+ peer->ip_pool = NULL;
+}
+
+static void dhcp_server_debug(const char *str, void *data)
+{
+ connman_info("%s: %s\n", (const char *) data, str);
+}
+
+static gboolean dhcp_server_started(gpointer data)
+{
+ struct connman_peer *peer = data;
+
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_READY);
+ connman_peer_unref(peer);
+
+ return FALSE;
+}
+
+static int start_dhcp_server(struct connman_peer *peer)
+{
+ const char *start_ip, *end_ip;
+ GDHCPServerError dhcp_error;
+ const char *broadcast;
+ const char *gateway;
+ const char *subnet;
+ int prefixlen;
+ int index;
+ int err;
+
+ DBG("");
+
+ err = -ENOMEM;
+
+ if (peer->sub_device)
+ index = connman_device_get_index(peer->sub_device);
+ else
+ index = connman_device_get_index(peer->device);
+
+ peer->ip_pool = __connman_ippool_create(index, 2, 1, NULL, NULL);
+ if (!peer->ip_pool)
+ goto error;
+
+ gateway = __connman_ippool_get_gateway(peer->ip_pool);
+ subnet = __connman_ippool_get_subnet_mask(peer->ip_pool);
+ broadcast = __connman_ippool_get_broadcast(peer->ip_pool);
+ start_ip = __connman_ippool_get_start_ip(peer->ip_pool);
+ end_ip = __connman_ippool_get_end_ip(peer->ip_pool);
+
+ prefixlen = connman_ipaddress_calc_netmask_len(subnet);
+
+ err = __connman_inet_modify_address(RTM_NEWADDR,
+ NLM_F_REPLACE | NLM_F_ACK, index, AF_INET,
+ gateway, NULL, prefixlen, broadcast);
+ if (err < 0)
+ goto error;
+
+ peer->dhcp_server = g_dhcp_server_new(G_DHCP_IPV4, index, &dhcp_error);
+ if (!peer->dhcp_server)
+ goto error;
+
+ g_dhcp_server_set_debug(peer->dhcp_server,
+ dhcp_server_debug, "Peer DHCP server");
+ g_dhcp_server_set_lease_time(peer->dhcp_server, 3600);
+ g_dhcp_server_set_option(peer->dhcp_server, G_DHCP_SUBNET, subnet);
+ g_dhcp_server_set_option(peer->dhcp_server, G_DHCP_ROUTER, gateway);
+ g_dhcp_server_set_option(peer->dhcp_server, G_DHCP_DNS_SERVER, NULL);
+ g_dhcp_server_set_ip_range(peer->dhcp_server, start_ip, end_ip);
+
+ err = g_dhcp_server_start(peer->dhcp_server);
+ if (err < 0)
+ goto error;
+
+ g_timeout_add_seconds(0, dhcp_server_started, connman_peer_ref(peer));
+
+ return 0;
+
+error:
+ stop_dhcp_server(peer);
+ return err;
+}
+
+static void reply_pending(struct connman_peer *peer, int error)
+{
+ if (!peer->pending)
+ return;
+
+ connman_dbus_reply_pending(peer->pending, error, NULL);
+ peer->pending = NULL;
+}
+
static void peer_free(gpointer data)
{
struct connman_peer *peer = data;
- connman_peer_destroy(peer);
+
+ reply_pending(peer, ENOENT);
+
+ connman_peer_unregister(peer);
+
+ if (peer->path) {
+ g_free(peer->path);
+ peer->path = NULL;
+ }
+
+ if (peer->ipconfig) {
+ __connman_ipconfig_set_ops(peer->ipconfig, NULL);
+ __connman_ipconfig_set_data(peer->ipconfig, NULL);
+ __connman_ipconfig_unref(peer->ipconfig);
+ peer->ipconfig = NULL;
+ }
+
+ stop_dhcp_server(peer);
+
+ if (peer->device) {
+ connman_device_unref(peer->device);
+ peer->device = NULL;
+ }
+
+ if (peer->services)
+ connman_peer_reset_services(peer);
+
+ g_free(peer->identifier);
+ g_free(peer->name);
+
+ g_free(peer);
+}
+
+static const char *state2string(enum connman_peer_state state)
+{
+ switch (state) {
+ case CONNMAN_PEER_STATE_UNKNOWN:
+ break;
+ case CONNMAN_PEER_STATE_IDLE:
+ return "idle";
+ case CONNMAN_PEER_STATE_ASSOCIATION:
+ return "association";
+ case CONNMAN_PEER_STATE_CONFIGURATION:
+ return "configuration";
+ case CONNMAN_PEER_STATE_READY:
+ return "ready";
+ case CONNMAN_PEER_STATE_DISCONNECT:
+ return "disconnect";
+ case CONNMAN_PEER_STATE_FAILURE:
+ return "failure";
+ }
+
+ return NULL;
+}
+
+static bool is_connecting(struct connman_peer *peer)
+{
+ if (peer->state == CONNMAN_PEER_STATE_ASSOCIATION ||
+ peer->state == CONNMAN_PEER_STATE_CONFIGURATION ||
+ peer->pending)
+ return true;
+
+ return false;
+}
+
+static bool is_connected(struct connman_peer *peer)
+{
+ if (peer->state == CONNMAN_PEER_STATE_READY)
+ return true;
+
+ return false;
+}
+
+static bool allow_property_changed(struct connman_peer *peer)
+{
+ if (g_hash_table_lookup_extended(peers_notify->add, peer->path,
+ NULL, NULL))
+ return false;
+
+ return true;
+}
+
+static void append_dhcp_server_ipv4(DBusMessageIter *iter, void *user_data)
+{
+ struct connman_peer *peer = user_data;
+ const char *str = "dhcp";
+ const char *gateway;
+ const char *subnet;
+
+ if (!peer->ip_pool)
+ return;
+
+ gateway = __connman_ippool_get_gateway(peer->ip_pool);
+ subnet = __connman_ippool_get_subnet_mask(peer->ip_pool);
+
+ connman_dbus_dict_append_basic(iter, "Method", DBUS_TYPE_STRING, &str);
+ connman_dbus_dict_append_basic(iter, "Address",
+ DBUS_TYPE_STRING, &gateway);
+ connman_dbus_dict_append_basic(iter, "Netmask",
+ DBUS_TYPE_STRING, &subnet);
+ connman_dbus_dict_append_basic(iter, "Gateway",
+ DBUS_TYPE_STRING, &gateway);
+}
+
+static void append_ipv4(DBusMessageIter *iter, void *user_data)
+{
+ struct connman_peer *peer = user_data;
+
+ if (!is_connected(peer))
+ return;
+
+ if (peer->connection_master)
+ append_dhcp_server_ipv4(iter, peer);
+ else if (peer->ipconfig)
+ __connman_ipconfig_append_ipv4(peer->ipconfig, iter);
+}
+
+static void append_peer_service(DBusMessageIter *iter,
+ struct _peer_service *service)
+{
+ DBusMessageIter dict;
+
+ connman_dbus_dict_open(iter, &dict);
+
+ switch (service->type) {
+ case CONNMAN_PEER_SERVICE_UNKNOWN:
+ /* Should never happen */
+ break;
+ case CONNMAN_PEER_SERVICE_WIFI_DISPLAY:
+ connman_dbus_dict_append_fixed_array(&dict,
+ "WiFiDisplayIEs", DBUS_TYPE_BYTE,
+ &service->data, service->length);
+ break;
+ }
+
+ connman_dbus_dict_close(iter, &dict);
+}
+
+static void append_peer_services(DBusMessageIter *iter, void *user_data)
+{
+ struct connman_peer *peer = user_data;
+ DBusMessageIter container;
+ GSList *list;
+
+ dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
+ NULL, &container);
+
+ if (!peer->services) {
+ DBusMessageIter dict;
+
+ connman_dbus_dict_open(&container, &dict);
+ connman_dbus_dict_close(&container, &dict);
+ } else {
+ for (list = peer->services; list; list = list->next)
+ append_peer_service(&container, list->data);
+ }
+
+ dbus_message_iter_close_container(iter, &container);
}
static void append_properties(DBusMessageIter *iter, struct connman_peer *peer)
{
- const char *state = "disconnected";
+ const char *state = state2string(peer->state);
DBusMessageIter dict;
connman_dbus_dict_open(iter, &dict);
@@ -55,11 +342,23 @@ static void append_properties(DBusMessageIter *iter, struct connman_peer *peer)
DBUS_TYPE_STRING, &state);
connman_dbus_dict_append_basic(&dict, "Name",
DBUS_TYPE_STRING, &peer->name);
- connman_dbus_dict_append_dict(&dict, "IPv4", NULL, NULL);
-
+ connman_dbus_dict_append_dict(&dict, "IPv4", append_ipv4, peer);
+ connman_dbus_dict_append_array(&dict, "Services",
+ DBUS_TYPE_DICT_ENTRY,
+ append_peer_services, peer);
connman_dbus_dict_close(iter, &dict);
}
+static void settings_changed(struct connman_peer *peer)
+{
+ if (!allow_property_changed(peer))
+ return;
+
+ connman_dbus_property_changed_dict(peer->path,
+ CONNMAN_PEER_INTERFACE, "IPv4",
+ append_ipv4, peer);
+}
+
static DBusMessage *get_peer_properties(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -92,31 +391,44 @@ static void append_peer_struct(gpointer key, gpointer value,
dbus_message_iter_close_container(array, &entry);
}
-struct _peers_notify {
- int id;
- GHashTable *add;
- GHashTable *remove;
-} *peers_notify;
+static void state_changed(struct connman_peer *peer)
+{
+ const char *state;
+
+ state = state2string(peer->state);
+ if (!state || !allow_property_changed(peer))
+ return;
+
+ connman_dbus_property_changed_basic(peer->path,
+ CONNMAN_PEER_INTERFACE, "State",
+ DBUS_TYPE_STRING, &state);
+}
static void append_existing_and_new_peers(gpointer key,
gpointer value, gpointer user_data)
{
struct connman_peer *peer = value;
DBusMessageIter *iter = user_data;
- DBusMessageIter entry;
+ DBusMessageIter entry, dict;
+
+ if (!peer || !peer->registered)
+ return;
if (g_hash_table_lookup(peers_notify->add, peer->path)) {
DBG("new %s", peer->path);
- append_peer_struct(key, value, user_data);
+ append_peer_struct(key, peer, iter);
g_hash_table_remove(peers_notify->add, peer->path);
- } else {
+ } else if (!g_hash_table_lookup(peers_notify->remove, peer->path)) {
DBG("existing %s", peer->path);
dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
NULL, &entry);
dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
&peer->path);
+ connman_dbus_dict_open(&entry, &dict);
+ connman_dbus_dict_close(&entry, &dict);
+
dbus_message_iter_close_container(iter, &entry);
}
}
@@ -195,32 +507,216 @@ static void peer_removed(struct connman_peer *peer)
peer_schedule_changed();
}
+static const char *get_dbus_sender(struct connman_peer *peer)
+{
+ if (!peer->pending)
+ return NULL;
+
+ return dbus_message_get_sender(peer->pending);
+}
+
+static enum connman_peer_wps_method check_wpspin(struct connman_peer *peer,
+ const char *wpspin)
+{
+ int len, i;
+
+ if (!wpspin)
+ return CONNMAN_PEER_WPS_PBC;
+
+ len = strlen(wpspin);
+ if (len == 0)
+ return CONNMAN_PEER_WPS_PBC;
+
+ if (len != 8)
+ return CONNMAN_PEER_WPS_UNKNOWN;
+ for (i = 0; i < 8; i++) {
+ if (!isdigit((unsigned char) wpspin[i]))
+ return CONNMAN_PEER_WPS_UNKNOWN;
+ }
+
+ return CONNMAN_PEER_WPS_PIN;
+}
+
+static void request_authorization_cb(struct connman_peer *peer,
+ bool choice_done, const char *wpspin,
+ const char *error, void *user_data)
+{
+ enum connman_peer_wps_method wps_method;
+ int err;
+
+ DBG("RequestInput return, %p", peer);
+
+ if (error) {
+ if (g_strcmp0(error,
+ "net.connman.Agent.Error.Canceled") == 0 ||
+ g_strcmp0(error,
+ "net.connman.Agent.Error.Rejected") == 0) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ if (!choice_done || !peer_driver->connect) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ wps_method = check_wpspin(peer, wpspin);
+
+ err = peer_driver->connect(peer, wps_method, wpspin);
+ if (err == -EINPROGRESS)
+ return;
+
+out:
+ reply_pending(peer, EIO);
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_IDLE);
+}
+
+static int peer_connect(struct connman_peer *peer)
+{
+ int err = -ENOTSUP;
+
+ if (peer_driver->connect)
+ err = peer_driver->connect(peer,
+ CONNMAN_PEER_WPS_UNKNOWN, NULL);
+
+ if (err == -ENOKEY) {
+ err = __connman_agent_request_peer_authorization(peer,
+ request_authorization_cb, true,
+ get_dbus_sender(peer), NULL);
+ }
+
+ return err;
+}
+
+static int peer_disconnect(struct connman_peer *peer)
+{
+ int err = -ENOTSUP;
+
+ connman_agent_cancel(peer);
+ reply_pending(peer, ECONNABORTED);
+
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_DISCONNECT);
+
+ if (peer->connection_master)
+ stop_dhcp_server(peer);
+ else
+ __connman_dhcp_stop(peer->ipconfig);
+
+ if (peer_driver->disconnect)
+ err = peer_driver->disconnect(peer);
+
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_IDLE);
+
+ return err;
+}
+
+static DBusMessage *connect_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_peer *peer = user_data;
+ GList *list, *start;
+ int err;
+
+ DBG("peer %p", peer);
+
+ if (peer->pending)
+ return __connman_error_in_progress(msg);
+
+ list = g_hash_table_get_values(peers_table);
+ start = list;
+ for (; list; list = list->next) {
+ struct connman_peer *temp = list->data;
+
+ if (temp == peer || temp->device != peer->device)
+ continue;
+
+ if (is_connecting(temp) || is_connected(temp)) {
+ if (peer_disconnect(temp) == -EINPROGRESS) {
+ g_list_free(start);
+ return __connman_error_in_progress(msg);
+ }
+ }
+ }
+
+ g_list_free(start);
+
+ peer->pending = dbus_message_ref(msg);
+
+ err = peer_connect(peer);
+ if (err == -EINPROGRESS)
+ return NULL;
+
+ if (err < 0) {
+ dbus_message_unref(peer->pending);
+ peer->pending = NULL;
+
+ return __connman_error_failed(msg, -err);
+ }
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *disconnect_peer(DBusConnection *conn,
+ DBusMessage *msg, void *user_data)
+{
+ struct connman_peer *peer = user_data;
+ int err;
+
+ DBG("peer %p", peer);
+
+ err = peer_disconnect(peer);
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
+
+ return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
struct connman_peer *connman_peer_create(const char *identifier)
{
struct connman_peer *peer;
peer = g_malloc0(sizeof(struct connman_peer));
- peer->identifier = g_strdup_printf("peer_%s", identifier);
+ peer->identifier = g_strdup(identifier);
+ peer->state = CONNMAN_PEER_STATE_IDLE;
+
+ peer->refcount = 1;
return peer;
}
-void connman_peer_destroy(struct connman_peer *peer)
+struct connman_peer *connman_peer_ref_debug(struct connman_peer *peer,
+ const char *file, int line, const char *caller)
{
- if (!peer)
+ DBG("%p ref %d by %s:%d:%s()", peer, peer->refcount + 1,
+ file, line, caller);
+
+ __sync_fetch_and_add(&peer->refcount, 1);
+
+ return peer;
+}
+
+void connman_peer_unref_debug(struct connman_peer *peer,
+ const char *file, int line, const char *caller)
+{
+ DBG("%p ref %d by %s:%d:%s()", peer, peer->refcount - 1,
+ file, line, caller);
+
+ if (__sync_fetch_and_sub(&peer->refcount, 1) != 1)
return;
- if (peer->path) {
- peer_removed(peer);
- g_dbus_unregister_interface(connection, peer->path,
- CONNMAN_PEER_INTERFACE);
- g_free(peer->path);
- }
+ if (!peer->registered && !peer->path)
+ return peer_free(peer);
- g_free(peer->identifier);
- g_free(peer->name);
+ g_hash_table_remove(peers_table, peer->path);
+}
- g_free(peer);
+const char *connman_peer_get_identifier(struct connman_peer *peer)
+{
+ if (!peer)
+ return NULL;
+
+ return peer->identifier;
}
void connman_peer_set_name(struct connman_peer *peer, const char *name)
@@ -229,12 +725,304 @@ void connman_peer_set_name(struct connman_peer *peer, const char *name)
peer->name = g_strdup(name);
}
+void connman_peer_set_device(struct connman_peer *peer,
+ struct connman_device *device)
+{
+ if (!peer || !device)
+ return;
+
+ peer->device = device;
+ connman_device_ref(device);
+}
+
+struct connman_device *connman_peer_get_device(struct connman_peer *peer)
+{
+ if (!peer)
+ return NULL;
+
+ return peer->device;
+}
+
+void connman_peer_set_sub_device(struct connman_peer *peer,
+ struct connman_device *device)
+{
+ if (!peer || !device || peer->sub_device)
+ return;
+
+ peer->sub_device = device;
+}
+
+void connman_peer_set_as_master(struct connman_peer *peer, bool master)
+{
+ if (!peer || !is_connecting(peer))
+ return;
+
+ peer->connection_master = master;
+}
+
+static void dhcp_callback(struct connman_ipconfig *ipconfig,
+ struct connman_network *network,
+ bool success, gpointer data)
+{
+ struct connman_peer *peer = data;
+ int err;
+
+ if (!success)
+ goto error;
+
+ DBG("lease acquired for ipconfig %p", ipconfig);
+
+ err = __connman_ipconfig_address_add(ipconfig);
+ if (err < 0)
+ goto error;
+
+ return;
+
+error:
+ __connman_ipconfig_address_remove(ipconfig);
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_FAILURE);
+}
+
+static int start_dhcp_client(struct connman_peer *peer)
+{
+ if (peer->sub_device)
+ __connman_ipconfig_set_index(peer->ipconfig,
+ connman_device_get_index(peer->sub_device));
+
+ __connman_ipconfig_enable(peer->ipconfig);
+
+ return __connman_dhcp_start(peer->ipconfig, NULL, dhcp_callback, peer);
+}
+
+static void report_error_cb(void *user_context, bool retry, void *user_data)
+{
+ struct connman_peer *peer = user_context;
+
+ if (retry) {
+ int err;
+ err = peer_connect(peer);
+
+ if (err == 0 || err == -EINPROGRESS)
+ return;
+ }
+
+ reply_pending(peer, ENOTCONN);
+
+ peer_disconnect(peer);
+
+ if (!peer->connection_master) {
+ __connman_dhcp_stop(peer->ipconfig);
+ __connman_ipconfig_disable(peer->ipconfig);
+ } else
+ stop_dhcp_server(peer);
+
+ peer->connection_master = false;
+ peer->sub_device = NULL;
+}
+
+static int manage_peer_error(struct connman_peer *peer)
+{
+ int err;
+
+ err = __connman_agent_report_peer_error(peer, peer->path,
+ "connect-failed", report_error_cb,
+ get_dbus_sender(peer), NULL);
+ if (err != -EINPROGRESS) {
+ report_error_cb(peer, false, NULL);
+ return err;
+ }
+
+ return 0;
+}
+
+int connman_peer_set_state(struct connman_peer *peer,
+ enum connman_peer_state new_state)
+{
+ enum connman_peer_state old_state = peer->state;
+ int err;
+
+ DBG("peer (%s) old state %d new state %d", peer->name,
+ old_state, new_state);
+
+ if (old_state == new_state)
+ return -EALREADY;
+
+ switch (new_state) {
+ case CONNMAN_PEER_STATE_UNKNOWN:
+ return -EINVAL;
+ case CONNMAN_PEER_STATE_IDLE:
+ if (is_connecting(peer) || is_connected(peer))
+ return peer_disconnect(peer);
+ peer->sub_device = NULL;
+ break;
+ case CONNMAN_PEER_STATE_ASSOCIATION:
+ break;
+ case CONNMAN_PEER_STATE_CONFIGURATION:
+ if (peer->connection_master)
+ err = start_dhcp_server(peer);
+ else
+ err = start_dhcp_client(peer);
+ if (err < 0)
+ return connman_peer_set_state(peer,
+ CONNMAN_PEER_STATE_FAILURE);
+ break;
+ case CONNMAN_PEER_STATE_READY:
+ reply_pending(peer, 0);
+ break;
+ case CONNMAN_PEER_STATE_DISCONNECT:
+ if (peer->connection_master)
+ stop_dhcp_server(peer);
+ peer->connection_master = false;
+ peer->sub_device = NULL;
+
+ break;
+ case CONNMAN_PEER_STATE_FAILURE:
+ if (manage_peer_error(peer) == 0)
+ return 0;
+ break;
+ };
+
+ peer->state = new_state;
+ state_changed(peer);
+
+ return 0;
+}
+
+int connman_peer_request_connection(struct connman_peer *peer)
+{
+ return __connman_agent_request_peer_authorization(peer,
+ request_authorization_cb, false,
+ NULL, NULL);
+}
+
+static void peer_service_free(gpointer data)
+{
+ struct _peer_service *service = data;
+
+ if (!service)
+ return;
+
+ g_free(service->data);
+ g_free(service);
+}
+
+void connman_peer_reset_services(struct connman_peer *peer)
+{
+ if (!peer)
+ return;
+
+ g_slist_free_full(peer->services, peer_service_free);
+ peer->services = NULL;
+}
+
+void connman_peer_services_changed(struct connman_peer *peer)
+{
+ if (!peer || !peer->registered || !allow_property_changed(peer))
+ return;
+
+ connman_dbus_property_changed_array(peer->path,
+ CONNMAN_PEER_INTERFACE, "Services",
+ DBUS_TYPE_DICT_ENTRY, append_peer_services, peer);
+}
+
+void connman_peer_add_service(struct connman_peer *peer,
+ enum connman_peer_service_type type,
+ const unsigned char *data, int data_length)
+{
+ struct _peer_service *service;
+
+ if (!peer || !data || type == CONNMAN_PEER_SERVICE_UNKNOWN)
+ return;
+
+ service = g_malloc0(sizeof(struct _peer_service));
+ service->type = type;
+ service->data = g_memdup(data, data_length * sizeof(unsigned char));
+ service->length = data_length;
+
+ peer->services = g_slist_prepend(peer->services, service);
+}
+
+static void peer_up(struct connman_ipconfig *ipconfig, const char *ifname)
+{
+ DBG("%s up", ifname);
+}
+
+static void peer_down(struct connman_ipconfig *ipconfig, const char *ifname)
+{
+ DBG("%s down", ifname);
+}
+
+static void peer_lower_up(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ DBG("%s lower up", ifname);
+}
+
+static void peer_lower_down(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
+
+ DBG("%s lower down", ifname);
+
+ __connman_ipconfig_disable(ipconfig);
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_DISCONNECT);
+}
+
+static void peer_ip_bound(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
+
+ DBG("%s ip bound", ifname);
+
+ settings_changed(peer);
+ connman_peer_set_state(peer, CONNMAN_PEER_STATE_READY);
+}
+
+static void peer_ip_release(struct connman_ipconfig *ipconfig,
+ const char *ifname)
+{
+ struct connman_peer *peer = __connman_ipconfig_get_data(ipconfig);
+
+ DBG("%s ip release", ifname);
+
+ settings_changed(peer);
+}
+
+static const struct connman_ipconfig_ops peer_ip_ops = {
+ .up = peer_up,
+ .down = peer_down,
+ .lower_up = peer_lower_up,
+ .lower_down = peer_lower_down,
+ .ip_bound = peer_ip_bound,
+ .ip_release = peer_ip_release,
+ .route_set = NULL,
+ .route_unset = NULL,
+};
+
+static struct connman_ipconfig *create_ipconfig(int index, void *user_data)
+{
+ struct connman_ipconfig *ipconfig;
+
+ ipconfig = __connman_ipconfig_create(index,
+ CONNMAN_IPCONFIG_TYPE_IPV4);
+ if (!ipconfig)
+ return NULL;
+
+ __connman_ipconfig_set_method(ipconfig, CONNMAN_IPCONFIG_METHOD_DHCP);
+ __connman_ipconfig_set_data(ipconfig, user_data);
+ __connman_ipconfig_set_ops(ipconfig, &peer_ip_ops);
+
+ return ipconfig;
+}
+
static const GDBusMethodTable peer_methods[] = {
{ GDBUS_METHOD("GetProperties",
NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
get_peer_properties) },
- { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, NULL) },
- { GDBUS_METHOD("Disconnect", NULL, NULL, NULL) },
+ { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connect_peer) },
+ { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect_peer) },
{ },
};
@@ -244,23 +1032,37 @@ static const GDBusSignalTable peer_signals[] = {
{ },
};
+static char *get_peer_path(struct connman_device *device,
+ const char *identifier)
+{
+ return g_strdup_printf("%s/peer/peer_%s_%s", CONNMAN_PATH,
+ connman_device_get_ident(device), identifier);
+}
+
int connman_peer_register(struct connman_peer *peer)
{
+ int index;
+
DBG("peer %p", peer);
- if (peer->path)
+ if (peer->path && peer->registered)
return -EALREADY;
- peer->path = g_strdup_printf("%s/peer/%s", CONNMAN_PATH,
- peer->identifier);
+ index = connman_device_get_index(peer->device);
+ peer->ipconfig = create_ipconfig(index, peer);
+ if (!peer->ipconfig)
+ return -ENOMEM;
+
+ peer->path = get_peer_path(peer->device, peer->identifier);
DBG("path %s", peer->path);
- g_hash_table_insert(peers_table, peer->identifier, peer);
+ g_hash_table_insert(peers_table, peer->path, peer);
g_dbus_register_interface(connection, peer->path,
CONNMAN_PEER_INTERFACE,
peer_methods, peer_signals,
NULL, peer, NULL);
+ peer->registered = true;
peer_added(peer);
return 0;
@@ -270,15 +1072,22 @@ void connman_peer_unregister(struct connman_peer *peer)
{
DBG("peer %p", peer);
- if (peer->path)
- g_hash_table_remove(peers_table, peer->identifier);
- else
- connman_peer_destroy(peer);
+ if (!peer->path || !peer->registered)
+ return;
+
+ connman_agent_cancel(peer);
+ reply_pending(peer, EIO);
+
+ g_dbus_unregister_interface(connection, peer->path,
+ CONNMAN_PEER_INTERFACE);
+ peer->registered = false;
+ peer_removed(peer);
}
-struct connman_peer *connman_peer_get(const char *identifier)
+struct connman_peer *connman_peer_get(struct connman_device *device,
+ const char *identifier)
{
- char *ident = g_strdup_printf("peer_%s", identifier);
+ char *ident = get_peer_path(device, identifier);
struct connman_peer *peer;
peer = g_hash_table_lookup(peers_table, ident);
@@ -287,11 +1096,41 @@ struct connman_peer *connman_peer_get(const char *identifier)
return peer;
}
+int connman_peer_driver_register(struct connman_peer_driver *driver)
+{
+ if (peer_driver && peer_driver != driver)
+ return -EINVAL;
+
+ peer_driver = driver;
+
+ __connman_peer_service_set_driver(driver);
+
+ return 0;
+}
+
+void connman_peer_driver_unregister(struct connman_peer_driver *driver)
+{
+ if (peer_driver != driver)
+ return;
+
+ peer_driver = NULL;
+
+ __connman_peer_service_set_driver(NULL);
+}
+
void __connman_peer_list_struct(DBusMessageIter *array)
{
g_hash_table_foreach(peers_table, append_peer_struct, array);
}
+const char *__connman_peer_get_path(struct connman_peer *peer)
+{
+ if (!peer || !peer->registered)
+ return NULL;
+
+ return peer->path;
+}
+
int __connman_peer_init(void)
{
DBG("");
@@ -313,5 +1152,7 @@ void __connman_peer_cleanup(void)
DBG("");
g_hash_table_destroy(peers_table);
+ peers_table = NULL;
dbus_connection_unref(connection);
+ connection = NULL;
}
diff --git a/src/peer_service.c b/src/peer_service.c
new file mode 100644
index 00000000..053672af
--- /dev/null
+++ b/src/peer_service.c
@@ -0,0 +1,429 @@
+/*
+ *
+ * Connection Manager
+ *
+ * Copyright (C) 2014 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 <errno.h>
+
+#include <gdbus.h>
+
+#include "connman.h"
+
+static DBusConnection *connection;
+
+struct _peer_service {
+ bool registered;
+ const char *owner;
+ DBusMessage *pending;
+
+ GBytes *specification;
+ GBytes *query;
+ int version;
+
+ bool master;
+};
+
+struct _peer_service_owner {
+ char *owner;
+ guint watch;
+ GList *services;
+};
+
+static struct connman_peer_driver *peer_driver;
+
+static GHashTable *owners_map;
+static GHashTable *services_map;
+static int peer_master;
+
+static void reply_pending(struct _peer_service *service, int error)
+{
+ if (!service->pending)
+ return;
+
+ connman_dbus_reply_pending(service->pending, error, NULL);
+ service->pending = NULL;
+}
+
+static struct _peer_service *find_peer_service(GBytes *specification,
+ GBytes *query, int version,
+ const char *owner, bool remove)
+{
+ struct _peer_service *service = NULL;
+ struct _peer_service_owner *ps_owner;
+ GList *list;
+
+ ps_owner = g_hash_table_lookup(services_map, specification);
+ if (!ps_owner)
+ return NULL;
+
+ if (owner && g_strcmp0(owner, ps_owner->owner) != 0)
+ return NULL;
+
+ for (list = ps_owner->services; list; list = list->next) {
+ service = list->data;
+
+ if (service->specification == specification)
+ break;
+
+ if (version) {
+ if (!service->version)
+ continue;
+ if (version != service->version)
+ continue;
+ }
+
+ if (query) {
+ if (!service->query)
+ continue;
+ if (g_bytes_equal(service->query, query))
+ continue;
+ }
+
+ if (g_bytes_equal(service->specification, specification))
+ break;
+ }
+
+ if (!service)
+ return NULL;
+
+ if (owner && remove)
+ ps_owner->services = g_list_delete_link(ps_owner->services,
+ list);
+
+ return service;
+}
+
+static void unregister_peer_service(struct _peer_service *service)
+{
+ gsize spec_length, query_length = 0;
+ const void *spec, *query = NULL;
+
+ if (!peer_driver || !service->specification)
+ return;
+
+ spec = g_bytes_get_data(service->specification, &spec_length);
+ if (service->query)
+ query = g_bytes_get_data(service->query, &query_length);
+
+ peer_driver->unregister_service(spec, spec_length, query,
+ query_length, service->version);
+}
+
+static void remove_peer_service(gpointer user_data)
+{
+ struct _peer_service *service = user_data;
+
+ reply_pending(service, ECONNABORTED);
+
+ if (service->registered)
+ unregister_peer_service(service);
+
+ if (service->specification) {
+ if (service->owner) {
+ find_peer_service(service->specification,
+ service->query, service->version,
+ service->owner, true);
+ }
+
+ g_hash_table_remove(services_map, service->specification);
+ g_bytes_unref(service->specification);
+ }
+
+ if (service->query)
+ g_bytes_unref(service->query);
+
+ if (service->master)
+ peer_master--;
+
+ g_free(service);
+}
+
+static void apply_peer_service_removal(gpointer user_data)
+{
+ struct _peer_service *service = user_data;
+
+ service->owner = NULL;
+ remove_peer_service(user_data);
+}
+
+static void remove_peer_service_owner(gpointer user_data)
+{
+ struct _peer_service_owner *ps_owner = user_data;
+
+ DBG("owner %s", ps_owner->owner);
+
+ if (ps_owner->watch > 0)
+ g_dbus_remove_watch(connection, ps_owner->watch);
+
+ if (ps_owner->services) {
+ g_list_free_full(ps_owner->services,
+ apply_peer_service_removal);
+ }
+
+ g_free(ps_owner->owner);
+ g_free(ps_owner);
+}
+
+static void owner_disconnect(DBusConnection *conn, void *user_data)
+{
+ struct _peer_service_owner *ps_owner = user_data;
+
+ ps_owner->watch = 0;
+ g_hash_table_remove(owners_map, ps_owner->owner);
+}
+
+static void service_registration_result(int result, void *user_data)
+{
+ struct _peer_service *service = user_data;
+
+ reply_pending(service, -result);
+
+ if (service->registered)
+ return;
+
+ if (result == 0) {
+ service->registered = true;
+ if (service->master)
+ peer_master++;
+ return;
+ }
+
+ remove_peer_service(service);
+}
+
+static int register_peer_service(struct _peer_service *service)
+{
+ gsize spec_length, query_length = 0;
+ const void *spec, *query = NULL;
+
+ if (!peer_driver)
+ return 0;
+
+ spec = g_bytes_get_data(service->specification, &spec_length);
+ if (service->query)
+ query = g_bytes_get_data(service->query, &query_length);
+
+ return peer_driver->register_service(spec, spec_length, query,
+ query_length, service->version,
+ service_registration_result, service);
+}
+
+static void register_all_services(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct _peer_service_owner *ps_owner = value;
+ GList *list;
+
+ for (list = ps_owner->services; list; list = list->next) {
+ struct _peer_service *service = list->data;
+
+ if (service->registered)
+ register_peer_service(service);
+ }
+}
+
+void __connman_peer_service_set_driver(struct connman_peer_driver *driver)
+{
+ peer_driver = driver;
+ if (!peer_driver)
+ return;
+
+ g_hash_table_foreach(owners_map, register_all_services, NULL);
+}
+
+int __connman_peer_service_register(const char *owner, DBusMessage *msg,
+ const unsigned char *specification,
+ int specification_length,
+ const unsigned char *query,
+ int query_length, int version,
+ bool master)
+{
+ struct _peer_service_owner *ps_owner;
+ GBytes *spec, *query_spec = NULL;
+ struct _peer_service *service;
+ bool new = false;
+ int ret = 0;
+
+ DBG("owner %s - spec %p/length %d - query %p/length %d - version %d",
+ owner,specification, specification_length,
+ query, query_length, version);
+
+ if (!specification || specification_length == 0)
+ return -EINVAL;
+
+ ps_owner = g_hash_table_lookup(owners_map, owner);
+ if (!ps_owner) {
+ ps_owner = g_try_new0(struct _peer_service_owner, 1);
+ if (!ps_owner)
+ return -ENOMEM;
+
+ ps_owner->owner = g_strdup(owner);
+ ps_owner->watch = g_dbus_add_disconnect_watch(connection,
+ owner, owner_disconnect,
+ ps_owner, NULL);
+ g_hash_table_insert(owners_map, ps_owner->owner, ps_owner);
+ new = true;
+ }
+
+ spec = g_bytes_new(specification, specification_length);
+ if (query)
+ query_spec = g_bytes_new(query, query_length);
+
+ service = find_peer_service(spec, query_spec, version, NULL, false);
+ if (service) {
+ DBG("Found one existing service %p", service);
+
+ if (g_strcmp0(service->owner, owner))
+ ret = -EBUSY;
+
+ if (service->pending)
+ ret = -EINPROGRESS;
+ else
+ ret = -EEXIST;
+
+ service = NULL;
+ goto error;
+ }
+
+ service = g_try_new0(struct _peer_service, 1);
+ if (!service) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ service->owner = ps_owner->owner;
+ service->specification = spec;
+ service->query = query_spec;
+ service->version = version;
+ service->master = master;
+
+ g_hash_table_insert(services_map, spec, ps_owner);
+ spec = query_spec = NULL;
+
+ ret = register_peer_service(service);
+ if (ret != 0 && ret != -EINPROGRESS)
+ goto error;
+ else if (ret == -EINPROGRESS)
+ service->pending = dbus_message_ref(msg);
+ else {
+ service->registered = true;
+ if (master)
+ peer_master++;
+ }
+
+ ps_owner->services = g_list_prepend(ps_owner->services, service);
+
+ return ret;
+error:
+ if (spec)
+ g_bytes_unref(spec);
+ if (query_spec)
+ g_bytes_unref(query_spec);
+
+ if (service)
+ remove_peer_service(service);
+
+ if (new)
+ g_hash_table_remove(owners_map, ps_owner->owner);
+
+ return ret;
+}
+
+int __connman_peer_service_unregister(const char *owner,
+ const unsigned char *specification,
+ int specification_length,
+ const unsigned char *query,
+ int query_length, int version)
+{
+ struct _peer_service_owner *ps_owner;
+ GBytes *spec, *query_spec = NULL;
+ struct _peer_service *service;
+
+ DBG("owner %s - spec %p/length %d - query %p/length %d - version %d",
+ owner,specification, specification_length,
+ query, query_length, version);
+
+ ps_owner = g_hash_table_lookup(owners_map, owner);
+ if (!ps_owner)
+ return -ESRCH;
+
+ spec = g_bytes_new(specification, specification_length);
+ if (query)
+ query_spec = g_bytes_new(query, query_length);
+
+ service = find_peer_service(spec, query_spec, version, owner, true);
+
+ g_bytes_unref(spec);
+ g_bytes_unref(query_spec);
+
+ if (!service)
+ return -ESRCH;
+
+ remove_peer_service(service);
+
+ if (!ps_owner->services)
+ g_hash_table_remove(owners_map, ps_owner->owner);
+
+ return 0;
+}
+
+bool connman_peer_service_is_master(void)
+{
+ if (!peer_master || !peer_driver)
+ return false;
+
+ return true;
+}
+
+int __connman_peer_service_init(void)
+{
+ DBG("");
+ connection = connman_dbus_get_connection();
+ if (!connection)
+ return -1;
+
+ peer_driver = NULL;
+
+ owners_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
+ remove_peer_service_owner);
+ services_map = g_hash_table_new_full(g_bytes_hash, g_bytes_equal,
+ NULL, NULL);
+ peer_master = 0;
+
+ return 0;
+}
+
+void __connman_peer_service_cleanup(void)
+{
+ DBG("");
+
+ if (!connection)
+ return;
+
+ g_hash_table_destroy(owners_map);
+ g_hash_table_destroy(services_map);
+ peer_master = 0;
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
diff --git a/src/service.c b/src/service.c
index cbca669e..87a2f2cd 100644
--- a/src/service.c
+++ b/src/service.c
@@ -234,6 +234,23 @@ enum connman_service_type __connman_service_string2type(const char *str)
return CONNMAN_SERVICE_TYPE_UNKNOWN;
}
+enum connman_service_security __connman_service_string2security(const char *str)
+{
+ if (!str)
+ return CONNMAN_SERVICE_SECURITY_UNKNOWN;
+
+ if (!strcmp(str, "psk"))
+ return CONNMAN_SERVICE_SECURITY_PSK;
+ if (!strcmp(str, "ieee8021x"))
+ return CONNMAN_SERVICE_SECURITY_8021X;
+ if (!strcmp(str, "none"))
+ return CONNMAN_SERVICE_SECURITY_NONE;
+ if (!strcmp(str, "wep"))
+ return CONNMAN_SERVICE_SECURITY_WEP;
+
+ return CONNMAN_SERVICE_SECURITY_UNKNOWN;
+}
+
static const char *security2string(enum connman_service_security security)
{
switch (security) {
@@ -302,18 +319,6 @@ static const char *error2string(enum connman_service_error error)
return NULL;
}
-static enum connman_service_error string2error(const char *error)
-{
- if (g_strcmp0(error, "dhcp-failed") == 0)
- return CONNMAN_SERVICE_ERROR_DHCP_FAILED;
- else if (g_strcmp0(error, "pin-missing") == 0)
- return CONNMAN_SERVICE_ERROR_PIN_MISSING;
- else if (g_strcmp0(error, "invalid-key") == 0)
- return CONNMAN_SERVICE_ERROR_INVALID_KEY;
-
- return CONNMAN_SERVICE_ERROR_UNKNOWN;
-}
-
static const char *proxymethod2string(enum connman_service_proxy_method method)
{
switch (method) {
@@ -480,15 +485,6 @@ static int service_load(struct connman_service *service)
service->favorite = g_key_file_get_boolean(keyfile,
service->identifier, "Favorite", NULL);
- str = g_key_file_get_string(keyfile,
- service->identifier, "Failure", NULL);
- if (str) {
- if (!service->favorite)
- service->state_ipv4 = service->state_ipv6 =
- CONNMAN_SERVICE_STATE_FAILURE;
- service->error = string2error(str);
- g_free(str);
- }
/* fall through */
case CONNMAN_SERVICE_TYPE_ETHERNET:
@@ -655,17 +651,9 @@ static int service_save(struct connman_service *service)
g_key_file_set_boolean(keyfile, service->identifier,
"Favorite", service->favorite);
- if (service->state_ipv4 == CONNMAN_SERVICE_STATE_FAILURE ||
- service->state_ipv6 == CONNMAN_SERVICE_STATE_FAILURE) {
- const char *failure = error2string(service->error);
- if (failure)
- g_key_file_set_string(keyfile,
- service->identifier,
- "Failure", failure);
- } else {
- g_key_file_remove_key(keyfile, service->identifier,
- "Failure", NULL);
- }
+ g_key_file_remove_key(keyfile, service->identifier,
+ "Failure", NULL);
+
/* fall through */
case CONNMAN_SERVICE_TYPE_ETHERNET:
@@ -2804,30 +2792,29 @@ void __connman_service_set_agent_identity(struct connman_service *service,
service->agent_identity);
}
-static int check_passphrase(struct connman_service *service,
- enum connman_service_security security,
- const char *passphrase)
+static int check_passphrase(enum connman_service_security security,
+ const char *passphrase)
{
guint i;
gsize length;
- if (!passphrase) {
- /*
- * This will prevent __connman_service_set_passphrase() to
- * wipe the passphrase out in case of -ENOKEY error for a
- * favorite service. */
- if (service->favorite)
- return 1;
- else
- return 0;
- }
+ if (!passphrase)
+ return 0;
length = strlen(passphrase);
switch (security) {
- case CONNMAN_SERVICE_SECURITY_PSK:
+ case CONNMAN_SERVICE_SECURITY_UNKNOWN:
+ case CONNMAN_SERVICE_SECURITY_NONE:
case CONNMAN_SERVICE_SECURITY_WPA:
case CONNMAN_SERVICE_SECURITY_RSN:
+
+ DBG("service security '%s' (%d) not handled",
+ security2string(security), security);
+
+ return -EOPNOTSUPP;
+
+ case CONNMAN_SERVICE_SECURITY_PSK:
/* A raw key is always 64 bytes length,
* its content is in hex representation.
* A PSK key must be between [8..63].
@@ -2852,8 +2839,7 @@ static int check_passphrase(struct connman_service *service,
} else if (length != 5 && length != 13)
return -ENOKEY;
break;
- case CONNMAN_SERVICE_SECURITY_UNKNOWN:
- case CONNMAN_SERVICE_SECURITY_NONE:
+
case CONNMAN_SERVICE_SECURITY_8021X:
break;
}
@@ -2864,25 +2850,29 @@ static int check_passphrase(struct connman_service *service,
int __connman_service_set_passphrase(struct connman_service *service,
const char *passphrase)
{
- int err = 0;
+ int err;
- if (service->immutable || service->hidden)
+ if (service->hidden)
+ return -EINVAL;
+
+ if (service->immutable &&
+ service->security != CONNMAN_SERVICE_SECURITY_8021X)
return -EINVAL;
- err = check_passphrase(service, service->security, passphrase);
+ err = check_passphrase(service->security, passphrase);
- if (err == 0) {
- g_free(service->passphrase);
- service->passphrase = g_strdup(passphrase);
+ if (err < 0)
+ return err;
- if (service->network)
- connman_network_set_string(service->network,
- "WiFi.Passphrase",
- service->passphrase);
- service_save(service);
- }
+ g_free(service->passphrase);
+ service->passphrase = g_strdup(passphrase);
- return err;
+ if (service->network)
+ connman_network_set_string(service->network, "WiFi.Passphrase",
+ service->passphrase);
+ service_save(service);
+
+ return 0;
}
const char *__connman_service_get_passphrase(struct connman_service *service)
@@ -2893,6 +2883,16 @@ const char *__connman_service_get_passphrase(struct connman_service *service)
return service->passphrase;
}
+static void clear_passphrase(struct connman_service *service)
+{
+ g_free(service->passphrase);
+ service->passphrase = NULL;
+
+ if (service->network)
+ connman_network_set_string(service->network, "WiFi.Passphrase",
+ service->passphrase);
+}
+
static DBusMessage *get_properties(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
@@ -3133,6 +3133,7 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
if (is_connecting_state(service, state) ||
is_connected_state(service, state))
__connman_network_clear_ipconfig(service->network, ipconfig);
+
__connman_ipconfig_unref(ipconfig);
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
@@ -3140,13 +3141,16 @@ int __connman_service_reset_ipconfig(struct connman_service *service,
else if (type == CONNMAN_IPCONFIG_TYPE_IPV6)
service->ipconfig_ipv6 = new_ipconfig;
- __connman_ipconfig_enable(new_ipconfig);
+ if (is_connecting_state(service, state) ||
+ is_connected_state(service, state))
+ __connman_ipconfig_enable(new_ipconfig);
if (new_state && new_method != old_method) {
if (type == CONNMAN_IPCONFIG_TYPE_IPV4)
*new_state = service->state_ipv4;
else
*new_state = service->state_ipv6;
+
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
}
@@ -3800,50 +3804,17 @@ static void remove_timeout(struct connman_service *service)
}
}
-void __connman_service_reply_dbus_pending(DBusMessage *pending, int error,
- const char *path)
-{
- if (pending) {
- if (error > 0) {
- DBusMessage *reply;
-
- reply = __connman_error_failed(pending, error);
- if (reply)
- g_dbus_send_message(connection, reply);
- } else {
- const char *sender;
-
- sender = dbus_message_get_interface(pending);
- if (!path)
- path = dbus_message_get_path(pending);
-
- DBG("sender %s path %s", sender, path);
-
- if (g_strcmp0(sender, CONNMAN_MANAGER_INTERFACE) == 0)
- g_dbus_send_reply(connection, pending,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- else
- g_dbus_send_reply(connection, pending,
- DBUS_TYPE_INVALID);
- }
-
- dbus_message_unref(pending);
- }
-}
-
static void reply_pending(struct connman_service *service, int error)
{
remove_timeout(service);
if (service->pending) {
- __connman_service_reply_dbus_pending(service->pending, error,
- NULL);
+ connman_dbus_reply_pending(service->pending, error, NULL);
service->pending = NULL;
}
if (service->provider_pending) {
- __connman_service_reply_dbus_pending(service->provider_pending,
+ connman_dbus_reply_pending(service->provider_pending,
error, service->path);
service->provider_pending = NULL;
}
@@ -3955,34 +3926,11 @@ static gboolean connect_timeout(gpointer user_data)
return FALSE;
}
-static bool is_interface_available(struct connman_service *service,
- struct connman_service *other_service)
-{
- unsigned int index = 0, other_index = 0;
-
- if (service->ipconfig_ipv4)
- index = __connman_ipconfig_get_index(service->ipconfig_ipv4);
- else if (service->ipconfig_ipv6)
- index = __connman_ipconfig_get_index(service->ipconfig_ipv6);
-
- if (other_service->ipconfig_ipv4)
- other_index = __connman_ipconfig_get_index(
- other_service->ipconfig_ipv4);
- else if (other_service->ipconfig_ipv6)
- other_index = __connman_ipconfig_get_index(
- other_service->ipconfig_ipv6);
-
- if (index > 0 && other_index != index)
- return true;
-
- return false;
-}
-
static DBusMessage *connect_service(DBusConnection *conn,
DBusMessage *msg, void *user_data)
{
struct connman_service *service = user_data;
- int err = 0;
+ int index, err = 0;
GList *list;
DBG("service %p", service);
@@ -3990,27 +3938,27 @@ static DBusMessage *connect_service(DBusConnection *conn,
if (service->pending)
return __connman_error_in_progress(msg);
+ index = __connman_service_get_index(service);
+
for (list = service_list; list; list = list->next) {
struct connman_service *temp = list->data;
- /*
- * We should allow connection if there are available
- * interfaces for a given technology type (like having
- * more than one wifi card).
- */
if (!is_connecting(temp) && !is_connected(temp))
break;
+ if (service == temp)
+ continue;
+
if (service->type != temp->type)
continue;
- if(!is_interface_available(service, temp)) {
- if (__connman_service_disconnect(temp) == -EINPROGRESS)
- err = -EINPROGRESS;
- }
+ if (__connman_service_get_index(temp) == index &&
+ __connman_service_disconnect(temp) == -EINPROGRESS)
+ err = -EINPROGRESS;
+
}
if (err == -EINPROGRESS)
- return __connman_error_in_progress(msg);
+ return __connman_error_operation_timeout(msg);
service->ignore = false;
@@ -4022,8 +3970,10 @@ static DBusMessage *connect_service(DBusConnection *conn,
if (err == -EINPROGRESS)
return NULL;
- dbus_message_unref(service->pending);
- service->pending = NULL;
+ if (service->pending) {
+ dbus_message_unref(service->pending);
+ service->pending = NULL;
+ }
if (err < 0)
return __connman_error_failed(msg, -err);
@@ -4042,10 +3992,8 @@ static DBusMessage *disconnect_service(DBusConnection *conn,
service->ignore = true;
err = __connman_service_disconnect(service);
- if (err < 0) {
- if (err != -EINPROGRESS)
- return __connman_error_failed(msg, -err);
- }
+ if (err < 0 && err != -EINPROGRESS)
+ return __connman_error_failed(msg, -err);
return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
}
@@ -4082,6 +4030,8 @@ bool __connman_service_remove(struct connman_service *service)
__connman_service_set_favorite(service, false);
+ __connman_ipconfig_ipv6_reset_privacy(service->ipconfig_ipv6);
+
service_save(service);
return true;
@@ -4397,13 +4347,13 @@ static void service_schedule_added(struct connman_service *service)
static void service_schedule_removed(struct connman_service *service)
{
- DBG("service %p %s", service, service->path);
-
if (!service || !service->path) {
DBG("service %p or path is NULL", service);
return;
}
+ DBG("service %p %s", service, service->path);
+
g_hash_table_remove(services_notify->add, service->path);
g_hash_table_replace(services_notify->remove, g_strdup(service->path),
NULL);
@@ -5003,10 +4953,8 @@ void __connman_service_set_string(struct connman_service *service,
} else if (g_str_equal(key, "Phase2")) {
g_free(service->phase2);
service->phase2 = g_strdup(value);
- } else if (g_str_equal(key, "Passphrase")) {
- g_free(service->passphrase);
- service->passphrase = g_strdup(value);
- }
+ } else if (g_str_equal(key, "Passphrase"))
+ __connman_service_set_passphrase(service, value);
}
void __connman_service_set_search_domains(struct connman_service *service,
@@ -5062,38 +5010,13 @@ static void report_error_cb(void *user_context, bool retry,
else {
/* It is not relevant to stay on Failure state
* when failing is due to wrong user input */
- service->state = CONNMAN_SERVICE_STATE_IDLE;
+ __connman_service_clear_error(service);
service_complete(service);
__connman_connection_update_gateway();
}
}
-int __connman_service_add_passphrase(struct connman_service *service,
- const gchar *passphrase)
-{
- int err = 0;
-
- switch (service->security) {
- case CONNMAN_SERVICE_SECURITY_WEP:
- case CONNMAN_SERVICE_SECURITY_PSK:
- case CONNMAN_SERVICE_SECURITY_8021X:
- err = __connman_service_set_passphrase(service, passphrase);
- break;
-
- case CONNMAN_SERVICE_SECURITY_UNKNOWN:
- case CONNMAN_SERVICE_SECURITY_NONE:
- case CONNMAN_SERVICE_SECURITY_WPA:
- case CONNMAN_SERVICE_SECURITY_RSN:
- DBG("service security '%s' (%d) not handled",
- security2string(service->security),
- service->security);
- break;
- }
-
- return err;
-}
-
static int check_wpspin(struct connman_service *service, const char *wpspin)
{
int length;
@@ -5187,7 +5110,7 @@ static void request_input_cb(struct connman_service *service,
__connman_service_set_agent_identity(service, identity);
if (passphrase)
- err = __connman_service_add_passphrase(service, passphrase);
+ err = __connman_service_set_passphrase(service, passphrase);
done:
if (err >= 0) {
@@ -5311,6 +5234,7 @@ static int service_indicate_state(struct connman_service *service)
{
enum connman_service_state old_state, new_state;
struct connman_service *def_service;
+ enum connman_ipconfig_method method;
int result;
if (!service)
@@ -5344,13 +5268,22 @@ static int service_indicate_state(struct connman_service *service)
service->state = new_state;
state_changed(service);
- if (new_state == CONNMAN_SERVICE_STATE_IDLE &&
- old_state != CONNMAN_SERVICE_STATE_DISCONNECT) {
+ switch(new_state) {
+ case CONNMAN_SERVICE_STATE_UNKNOWN:
- __connman_service_disconnect(service);
- }
+ break;
+
+ case CONNMAN_SERVICE_STATE_IDLE:
+ if (old_state != CONNMAN_SERVICE_STATE_DISCONNECT)
+ __connman_service_disconnect(service);
+
+ break;
+
+ case CONNMAN_SERVICE_STATE_ASSOCIATION:
- if (new_state == CONNMAN_SERVICE_STATE_CONFIGURATION) {
+ break;
+
+ case CONNMAN_SERVICE_STATE_CONFIGURATION:
if (!service->new_service &&
__connman_stats_service_register(service) == 0) {
/*
@@ -5362,11 +5295,10 @@ static int service_indicate_state(struct connman_service *service)
__connman_stats_get(service, true,
&service->stats_roaming.data);
}
- }
- if (new_state == CONNMAN_SERVICE_STATE_READY) {
- enum connman_ipconfig_method method;
+ break;
+ case CONNMAN_SERVICE_STATE_READY:
if (service->new_service &&
__connman_stats_service_register(service) == 0) {
/*
@@ -5426,7 +5358,16 @@ static int service_indicate_state(struct connman_service *service)
else if (service->type != CONNMAN_SERVICE_TYPE_VPN)
vpn_auto_connect();
- } else if (new_state == CONNMAN_SERVICE_STATE_DISCONNECT) {
+ break;
+
+ case CONNMAN_SERVICE_STATE_ONLINE:
+
+ break;
+
+ case CONNMAN_SERVICE_STATE_DISCONNECT:
+
+ reply_pending(service, ECONNABORTED);
+
def_service = __connman_service_get_default();
if (!__connman_notifier_is_connected() &&
@@ -5452,9 +5393,9 @@ static int service_indicate_state(struct connman_service *service)
downgrade_connected_services();
__connman_service_auto_connect(CONNMAN_SERVICE_CONNECT_REASON_AUTO);
- }
+ break;
- if (new_state == CONNMAN_SERVICE_STATE_FAILURE) {
+ case CONNMAN_SERVICE_STATE_FAILURE:
if (service->connect_reason == CONNMAN_SERVICE_CONNECT_REASON_USER &&
connman_agent_report_error(service, service->path,
@@ -5464,7 +5405,11 @@ static int service_indicate_state(struct connman_service *service)
NULL) == -EINPROGRESS)
return 0;
service_complete(service);
- } else
+
+ break;
+ }
+
+ if (new_state != CONNMAN_SERVICE_STATE_FAILURE)
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
service_list_sort();
@@ -5502,7 +5447,7 @@ int __connman_service_indicate_error(struct connman_service *service,
*/
if (service->error == CONNMAN_SERVICE_ERROR_INVALID_KEY ||
service->security == CONNMAN_SERVICE_SECURITY_8021X)
- __connman_service_set_passphrase(service, NULL);
+ clear_passphrase(service);
__connman_service_set_agent_identity(service, NULL);
@@ -5517,6 +5462,8 @@ int __connman_service_indicate_error(struct connman_service *service,
int __connman_service_clear_error(struct connman_service *service)
{
+ DBusMessage *pending, *provider_pending;
+
DBG("service %p", service);
if (!service)
@@ -5525,25 +5472,23 @@ int __connman_service_clear_error(struct connman_service *service)
if (service->state != CONNMAN_SERVICE_STATE_FAILURE)
return -EINVAL;
- service->state_ipv4 = service->state_ipv6 =
- CONNMAN_SERVICE_STATE_UNKNOWN;
- set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
+ pending = service->pending;
+ service->pending = NULL;
+ provider_pending = service->provider_pending;
+ service->provider_pending = NULL;
__connman_service_ipconfig_indicate_state(service,
- CONNMAN_SERVICE_STATE_IDLE,
- CONNMAN_IPCONFIG_TYPE_IPV6);
-
- /*
- * Toggling the IPv6 state to IDLE could trigger the auto connect
- * machinery and consequently the IPv4 state.
- */
- if (service->state_ipv4 != CONNMAN_SERVICE_STATE_UNKNOWN &&
- service->state_ipv4 != CONNMAN_SERVICE_STATE_FAILURE)
- return 0;
+ CONNMAN_SERVICE_STATE_IDLE,
+ CONNMAN_IPCONFIG_TYPE_IPV6);
- return __connman_service_ipconfig_indicate_state(service,
+ __connman_service_ipconfig_indicate_state(service,
CONNMAN_SERVICE_STATE_IDLE,
CONNMAN_IPCONFIG_TYPE_IPV4);
+
+ service->pending = pending;
+ service->provider_pending = provider_pending;
+
+ return 0;
}
int __connman_service_indicate_default(struct connman_service *service)
@@ -5708,38 +5653,45 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
enum connman_ipconfig_type type)
{
struct connman_ipconfig *ipconfig = NULL;
- enum connman_service_state old_state;
+ enum connman_service_state *old_state;
enum connman_ipconfig_method method;
if (!service)
return -EINVAL;
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
- old_state = service->state_ipv4;
+ switch (type) {
+ case CONNMAN_IPCONFIG_TYPE_UNKNOWN:
+ return -EINVAL;
+
+ case CONNMAN_IPCONFIG_TYPE_IPV4:
+ old_state = &service->state_ipv4;
ipconfig = service->ipconfig_ipv4;
- } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
- old_state = service->state_ipv6;
+
+ break;
+
+ case CONNMAN_IPCONFIG_TYPE_IPV6:
+ old_state = &service->state_ipv6;
ipconfig = service->ipconfig_ipv6;
+
+ break;
}
if (!ipconfig)
return -EINVAL;
/* Any change? */
- if (old_state == new_state)
+ if (*old_state == new_state)
return -EALREADY;
- DBG("service %p (%s) state %d (%s) type %d (%s)",
+ DBG("service %p (%s) old state %d (%s) new state %d (%s) type %d (%s)",
service, service ? service->identifier : NULL,
+ *old_state, state2string(*old_state),
new_state, state2string(new_state),
type, __connman_ipconfig_type2string(type));
switch (new_state) {
case CONNMAN_SERVICE_STATE_UNKNOWN:
case CONNMAN_SERVICE_STATE_IDLE:
- if (service->state == CONNMAN_SERVICE_STATE_FAILURE)
- return -EINVAL;
- break;
case CONNMAN_SERVICE_STATE_ASSOCIATION:
break;
case CONNMAN_SERVICE_STATE_CONFIGURATION:
@@ -5772,25 +5724,23 @@ int __connman_service_ipconfig_indicate_state(struct connman_service *service,
the state to IDLE so that it will not affect the combined state
in the future.
*/
- if (type == CONNMAN_IPCONFIG_TYPE_IPV4) {
- method = __connman_ipconfig_get_method(service->ipconfig_ipv4);
-
- if (method == CONNMAN_IPCONFIG_METHOD_OFF ||
- method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
- new_state = CONNMAN_SERVICE_STATE_IDLE;
-
- service->state_ipv4 = new_state;
-
- } else if (type == CONNMAN_IPCONFIG_TYPE_IPV6) {
- method = __connman_ipconfig_get_method(service->ipconfig_ipv6);
+ method = __connman_ipconfig_get_method(ipconfig);
+ switch (method) {
+ case CONNMAN_IPCONFIG_METHOD_UNKNOWN:
+ case CONNMAN_IPCONFIG_METHOD_OFF:
+ new_state = CONNMAN_SERVICE_STATE_IDLE;
+ break;
- if (method == CONNMAN_IPCONFIG_METHOD_OFF ||
- method == CONNMAN_IPCONFIG_METHOD_UNKNOWN)
- new_state = CONNMAN_SERVICE_STATE_IDLE;
+ case CONNMAN_IPCONFIG_METHOD_FIXED:
+ case CONNMAN_IPCONFIG_METHOD_MANUAL:
+ case CONNMAN_IPCONFIG_METHOD_DHCP:
+ case CONNMAN_IPCONFIG_METHOD_AUTO:
+ break;
- service->state_ipv6 = new_state;
}
+ *old_state = new_state;
+
update_nameservers(service);
return service_indicate_state(service);
@@ -5896,10 +5846,9 @@ static int service_connect(struct connman_service *service)
if (!service->wps ||
!connman_network_get_bool(service->network, "WiFi.UseWPS"))
return -ENOKEY;
- } else if (service->error ==
- CONNMAN_SERVICE_ERROR_INVALID_KEY)
- return -ENOKEY;
+ }
break;
+
case CONNMAN_SERVICE_SECURITY_8021X:
if (!service->eap)
return -EINVAL;
@@ -5995,13 +5944,23 @@ int __connman_service_connect(struct connman_service *service,
case CONNMAN_SERVICE_TYPE_GPS:
case CONNMAN_SERVICE_TYPE_P2P:
return -EINVAL;
- default:
- if (!is_ipconfig_usable(service))
- return -ENOLINK;
- err = service_connect(service);
+ case CONNMAN_SERVICE_TYPE_ETHERNET:
+ case CONNMAN_SERVICE_TYPE_GADGET:
+ case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+ case CONNMAN_SERVICE_TYPE_CELLULAR:
+ case CONNMAN_SERVICE_TYPE_VPN:
+ case CONNMAN_SERVICE_TYPE_WIFI:
+ break;
}
+ if (!is_ipconfig_usable(service))
+ return -ENOLINK;
+
+ __connman_service_clear_error(service);
+
+ err = service_connect(service);
+
service->connect_reason = reason;
if (err >= 0) {
set_error(service, CONNMAN_SERVICE_ERROR_UNKNOWN);
diff --git a/src/session.c b/src/session.c
index 00ef3696..08facc1d 100644
--- a/src/session.c
+++ b/src/session.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2007-2014 Intel Corporation. All rights reserved.
- * Copyright (C) 2011-2014 BWM CarIT GmbH. All rights reserved.
+ * Copyright (C) 2011-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/shared/netlink.c b/src/shared/netlink.c
index d72294cc..b32ab854 100644
--- a/src/shared/netlink.c
+++ b/src/shared/netlink.c
@@ -3,7 +3,7 @@
* Connection Manager
*
* Copyright (C) 2011-2012 Intel Corporation. All rights reserved.
- * Copyright (C) 2013 BWM CarIT GmbH.
+ * Copyright (C) 2013-2014 BMW Car IT GmbH.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/src/stats.c b/src/stats.c
index df5ab4eb..26343b13 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -2,7 +2,7 @@
*
* Connection Manager
*
- * Copyright (C) 2010 BMW Car IT GmbH. All rights reserved.
+ * Copyright (C) 2010-2014 BMW Car IT GmbH.
*
* 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
diff --git a/src/tethering.c b/src/tethering.c
index c7e17f5d..ceeec746 100644
--- a/src/tethering.c
+++ b/src/tethering.c
@@ -222,7 +222,7 @@ void __connman_tethering_set_enabled(void)
end_ip = __connman_ippool_get_end_ip(dhcp_ippool);
err = __connman_bridge_enable(BRIDGE_NAME, gateway,
- __connman_ipaddress_netmask_prefix_len(subnet_mask),
+ connman_ipaddress_calc_netmask_len(subnet_mask),
broadcast);
if (err < 0 && err != -EALREADY) {
__connman_ippool_unref(dhcp_ippool);
@@ -267,7 +267,7 @@ void __connman_tethering_set_enabled(void)
return;
}
- prefixlen = __connman_ipaddress_netmask_prefix_len(subnet_mask);
+ prefixlen = connman_ipaddress_calc_netmask_len(subnet_mask);
err = __connman_nat_enable(BRIDGE_NAME, start_ip, prefixlen);
if (err < 0) {
connman_error("Cannot enable NAT %d/%s", err, strerror(-err));
@@ -340,8 +340,7 @@ static void setup_tun_interface(unsigned int flags, unsigned change,
subnet_mask = __connman_ippool_get_subnet_mask(pn->pool);
server_ip = __connman_ippool_get_start_ip(pn->pool);
peer_ip = __connman_ippool_get_end_ip(pn->pool);
- prefixlen =
- __connman_ipaddress_netmask_prefix_len(subnet_mask);
+ prefixlen = connman_ipaddress_calc_netmask_len(subnet_mask);
if ((__connman_inet_modify_address(RTM_NEWADDR,
NLM_F_REPLACE | NLM_F_ACK, pn->index, AF_INET,
diff --git a/src/timeserver.c b/src/timeserver.c
index d41fa404..f0d33e5e 100644
--- a/src/timeserver.c
+++ b/src/timeserver.c
@@ -117,7 +117,7 @@ static void resolv_result(GResolvResultStatus status, char **results,
* Once the timeserver list (ts_list) is created, we start querying the
* servers one by one. If resolving fails on one of them, we move to the
* next one. The user can enter either an IP address or a URL for the
- * timeserver. We only resolve the urls. Once we have a IP for the NTP
+ * timeserver. We only resolve the URLs. Once we have an IP for the NTP
* server, we start querying it for time corrections.
*/
void __connman_timeserver_sync_next()
@@ -137,7 +137,7 @@ void __connman_timeserver_sync_next()
ts_list = g_slist_delete_link(ts_list, ts_list);
- /* if its a IP , directly query it. */
+ /* if it's an IP, directly query it. */
if (connman_inet_check_ipaddress(ts_current) > 0) {
DBG("Using timeserver %s", ts_current);
@@ -146,7 +146,7 @@ void __connman_timeserver_sync_next()
return;
}
- DBG("Resolving server %s", ts_current);
+ DBG("Resolving timeserver %s", ts_current);
resolv_id = g_resolv_lookup_hostname(resolv, ts_current,
resolv_result, NULL);
@@ -200,7 +200,7 @@ GSList *__connman_timeserver_get_all(struct connman_service *service)
service_ts = connman_service_get_timeservers(service);
- /* First add Service Timeservers via DHCP to the list */
+ /* Then add Service Timeservers via DHCP to the list */
for (i = 0; service_ts && service_ts[i]; i++)
list = __connman_timeserver_add_list(list, service_ts[i]);
@@ -286,7 +286,7 @@ static void ts_recheck_enable(void)
/*
* This function must be called everytime the default service changes, the
- * service timeserver(s) or gatway changes or the global timeserver(s) changes.
+ * service timeserver(s) or gateway changes or the global timeserver(s) changes.
*/
int __connman_timeserver_sync(struct connman_service *default_service)
{
diff --git a/src/wispr.c b/src/wispr.c
index dcce93cc..c4fcd60b 100644
--- a/src/wispr.c
+++ b/src/wispr.c
@@ -711,6 +711,11 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data)
DBG("status: %03u", status);
switch (status) {
+ case 000:
+ __connman_agent_request_browser(wp_context->service,
+ wispr_portal_browser_reply_cb,
+ wp_context->status_url, wp_context);
+ break;
case 200:
if (wp_context->wispr_msg.message_type >= 0)
break;
@@ -755,6 +760,11 @@ static bool wispr_portal_web_result(GWebResult *result, gpointer user_data)
}
break;
+ case 505:
+ __connman_agent_request_browser(wp_context->service,
+ wispr_portal_browser_reply_cb,
+ wp_context->status_url, wp_context);
+ break;
default:
break;
}