[RFC] Wi-Fi Protected Setup (WPS) connection
by Jose Blanquicet
Hello everybody,
We would like to propose a RFC to change the way to manage the WPS
connections. Following we present our proposal and the reasons for
suggesting it:
Current implementation of WPS connection requires to specify the service to
which the user wants to connect, and when the connection is going to
finalize, a verification is done in *handle_wps_completion* function to
ensure that the SSID of the AP actually being connected was the one
specified by the user. This violates the WiFi Alliance specification over
WPS and the WPS Certification plan because:
1. WiFi Alliance admits to certify devices that have no mean for the
user to choose an AP to connect to, they define them as "Client devices
with only a simple display or a fixed label containing a setup password"
(Pag. 12 of Wi-Fi Simple Configuration Technical Specification Version
2.0.5)
1. The WPS protocol includes the transition from un-configured to
configured state of the AP when the first Enrollee connects, some Access
Points change their SSID during this transition, that would cause the
ConnMan to invalidate the connection. A tipical example of such Access
Point is the Atheros used in test 5.4.2 of Wi-Fi CERTIFIED™ Wi-Fi Protected
Setup™ Interoperability Test Plan – Version 2.0.15
After having performed a detailed study of the wpa_supplicant
implementation for the WPS, we propose to implement a solution with the
following general characteristics:
1. The new implementation must keep current WPS implementation for
compatibility support, but as deprecated.
2. In order to meet the specifications of Wi-Fi Alliance and based on
what the WPS D-Bus Interface of wpa_supplicant offers (Documented in
https://w1.fi/wpa_supplicant/devel/dbus.html#dbus_wps) we propose to add
two methods to the Technology D-Bus Interface: *StartWPS* and *CancelWPS*,
analogous to functions WPS.Start and WPS.Cancel provided by
wpa_supplicant. In this way there is no service specified enabling simple
devices to offer a very basic interface to the user for starting the WPS
session. Both methods would be supported only by WiFi technology.
3. On the other hand, some advanced WiFi modules expose more than one
network interface (one for P2P, one for STA, one for AP ..) that can be
active at the same time, and it is then desirable to not let connman
randomly choose on which start WPS, thus we propose also to add the
possibility to specify the interface over which either the start or cancel
action will be performed. This would not be a mandatory parameter in order
to keep the things easy for more simple systems.
Please find below the implementation proposal:
*StartWPS:*
Following the approach of wpa_supplicant, we propose to add the possibility
to choose which role to assume (enrollee, registrar), which authentication
type use (pin, pbc) and get back the pin to be used (if required), as well
as wpa_supplicant does. At this point, we can briefly define a possible
prototype of the method:
dict StartWPS(dict parameters)
Where the returned dictionary could be empty or composed by at most one
entry, which will be the just generated PIN by the wpa_supplicant, in case
it was requested. On the other hand, the function would receive a
dictionary with possible keys: “Ifname", "Role", "Type" and "Pin"; where
“Ifame” is an optional parameters covering previous defined characteristic
for complex systems. Whereas, parameters "Role", "Type" and "Pin" follow
exactly the same behavior of the table presented in
https://w1.fi/wpa_supplicant/devel/dbus.html#dbus_wps for method Start
of fi.w1.wpa_supplicant1.Interface.WPS
Interface.
When the *StartWPS* method gets called, it should verify if interface was
specified through “Ifname” entry key. If so, WPS Session will be started in
that specific interface, otherwise we suggest to look for the first
available interface with the capabilities to start a WPS Session among the
device_list of the Wi-Fi Technology. If it is found, then use it, if not
return "[service].Error.NotSupported”.
Additionally, current implementation does not allow to start a WPS Session
when the device is playing as Access Point (Tethering). On the contrary,
wpa_supplicant does. Therefore, we propose to also add this possibility to
the new implementation. It would be possible if a Service D-Bus Object is
not required for starting a WPS Session, which would be true if the new
methods are added to the Technology D-Bus Interface, as we propose.
*CancelWPS:*
This function does not require for any particular parameter. So, we propose
to only continue giving the option to specify the interface. Therefore, the
possible prototype of the method would be:
void CancelWPS(dict parameters)
Where the received dictionary could be empty or composed by at most one
single entry if the user wants to specify the interface using the key
“Ifname”. If so, the *CancelWPS* function should cancel the ongoing WPS
Session running in that specific interface. Otherwise, we suggest to do it
over all the Device of the Wi-Fi Technology (device_list).
*Going into details of implementation*:
After having studied the ConnMan architecture we think to associate the WPS
concept to the Device Infrastructure because if we want to add the
possibility of specify the interface (“Ifname”), the Device is the
corresponding represents of a real device inside the ConnMan. Therefore, we
think it is the best choice. Additionally, *StartWPS* and *CancelWPS*
should be added to the device driver:
*static* *struct* connman_device_driver wifi_ng_driver = {
.name = "*wifi*",
.type = *CONNMAN_DEVICE_TYPE_WIFI*,
...
.start_wps = wifi_start_wps,
.cancel_wps = wifi_cancel_wps,
};
It means that WiFi plugging must implements both methods wifi_start_wps and
wifi_cancel_wps. In particular, wifi_start_wps will need to receive the WPS
parameters to then pass them to the ConnMan’s supplicant handler
(gsuppicant/supplicant.c), which is the only one that interacts directly
with the wpa_supplicant.
Next, the supplicant handler will call methods Start or Cancel of the
fi.w1.wpa_supplicant1.Interface.WPS
D-Bus Interface of the wpa_supplicant, with the required parameters. In
case the method Start returns the newly generated PIN it has to be
forwarded towards the Technology to then be added as an entry in the
directory that would be returned by the *StartWPS* method. It would imply
that we have to store the request message of the *StartWPS* method in order
to reply possibly with a the PIN generated by the wpa_supplicant. To do it,
we propose to store that message in the Device structure in order to be
coherent with the association we previously proposed between the WPS and
Device.
Once the WPS Session has been initiated, it could finalize successfully or
fail. The current implementation does not provide further information about
such a events. Given that, we propose to notify the following events (Just
the most commons):
- Success: WPS provisioning has finished successfully.
- Password Authentication Fail: When pin entered in the registrar was
wrong.
- PBC-Overlap: When an enrollee detects two registrars with PBC session
active.
We think to perform those notifications using a D-Bus Signal added to the
Technology Interface, let’s call it *WPSEvent*. It would simply indicate
when one of the described event takes place. We propose to just provide a
string with the name of the event: "success", "pwd-auth-fail" or
"pbc-overlap", following the wpa_supplicant notation. All this information
is already provided by the wpa_supplicant in the event
fi.w1.wpa_supplicant1.Interface.WPS.Event, thus it just need to be
forwarded to the Technology in order to be emitted.
In order to forward WPS events, we propose to follow the implementation of
the communication between the plug-in and the supplicant handler, it means
to use the callback mechanism adding a new callback:
*static* *const* GSupplicantCallbacks callbacks = {
...
.wps_event = wps_event,
};
Thus the wifi plug-in must implement the wps_event function that will
basically just call a Technology function that will emit the proposed
signal.
What do you think about our proposal? Of course, everybody is welcome to
give feedbacks and suggestions.
Best regards,
Jose Blanquicet
4 years, 7 months
[PATCH] dhcp: Set link MTU if available
by Patrik Flykt
Request DHCP Interface MTU option from the DHCP server and set the
MTU if it is between the minimum required for IPv6 and the maximum
for ethernet networks.
Reported by auto.
---
Please test,
Patrik
gdhcp/common.c | 1 +
gdhcp/gdhcp.h | 1 +
src/dhcp.c | 20 ++++++++++++++++++++
3 files changed, 22 insertions(+)
diff --git a/gdhcp/common.c b/gdhcp/common.c
index f3d4677..3817bcc 100644
--- a/gdhcp/common.c
+++ b/gdhcp/common.c
@@ -46,6 +46,7 @@ static const DHCPOption client_options[] = {
{ OPTION_IP | OPTION_LIST, 0x06 }, /* domain-name-servers */
{ OPTION_STRING, 0x0c }, /* hostname */
{ OPTION_STRING, 0x0f }, /* domain-name */
+ { OPTION_U16, 0x1a }, /* mtu */
{ OPTION_IP | OPTION_LIST, 0x2a }, /* ntp-servers */
{ OPTION_U32, 0x33 }, /* dhcp-lease-time */
/* Options below will not be exposed to user */
diff --git a/gdhcp/gdhcp.h b/gdhcp/gdhcp.h
index 0ed7fa5..3dcb7a5 100644
--- a/gdhcp/gdhcp.h
+++ b/gdhcp/gdhcp.h
@@ -77,6 +77,7 @@ typedef enum {
#define G_DHCP_DNS_SERVER 0x06
#define G_DHCP_DOMAIN_NAME 0x0f
#define G_DHCP_HOST_NAME 0x0c
+#define G_DHCP_MTU 0x1a
#define G_DHCP_NTP_SERVER 0x2a
#define G_DHCP_CLIENT_ID 0x3d
diff --git a/src/dhcp.c b/src/dhcp.c
index 4040ad1..1d2cd48 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -26,6 +26,11 @@
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <net/ethernet.h>
+
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
#include <connman/ipconfig.h>
#include <include/setting.h>
@@ -327,6 +332,20 @@ static bool apply_lease_available_on_network(GDHCPClient *dhcp_client,
return false;
}
+ option = g_dhcp_client_get_option(dhcp_client, G_DHCP_MTU);
+ if (option && option->data) {
+ int mtu, index, err;
+
+ mtu = atoi(option->data);
+
+ if (mtu >= IPV6_MIN_MTU && mtu <= ETH_DATA_LEN) {
+ index = __connman_ipconfig_get_index(dhcp->ipconfig);
+ err = connman_inet_set_mtu(index, mtu);
+
+ DBG("MTU %d index %d err %d", mtu, index, err);
+ }
+ }
+
option = g_dhcp_client_get_option(dhcp_client, 252);
if (option)
pac = g_strdup(option->data);
@@ -544,6 +563,7 @@ static int dhcp_initialize(struct connman_dhcp *dhcp)
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_MTU);
}
g_dhcp_client_set_request(dhcp_client, G_DHCP_SUBNET);
--
2.8.0.rc3
4 years, 8 months
[PATCH] plugins/wifi: Do not disable network on Disconnect
by naveen@nestlabs.com
From: Naveen Singh <nasingh(a)google.com>
Connman currently disables network on a disconnect event. This severely
impacts wpa supplicant ability to roam to same or different BSSID. The
act of disabling network disables the complete network profile in wpa
supplicant and it does not try to connect on its own and then waits for
a new connection attempt from connman. This delays the re-connection
timings. Once a network is disabled, wpa supplicant will generate a
locally generated deauth while a connection is going through.
wpa_supplicant is currently has the best knowledge of getting back L2 level
connectivity.With this change this is how it would appear in log lines
when a deauth with reason code 7/6/4 is received:
1. wpa_supplicant gets the reason code 7 deauth
2. wpa_supplicant starts a fast connect attempt
3. wpa_supplicant generates a disconnect notification to connman
4. connman calls set_disconnected which would make device lose its
current IP address.
5. service is disconnected as well.
6. wpa_supplicant gets device connected back to same AP in this case
7. wpa_supplicant generates connected event.
8. connman starts with DHCP request (having same IP as the previous
one).
---
plugins/wifi.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/plugins/wifi.c b/plugins/wifi.c
index bb1cabc..382ed81 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -2407,12 +2407,6 @@ static void interface_state(GSupplicantInterface *interface)
network, wifi))
break;
- /* We disable the selected network, if not then
- * wpa_supplicant will loop retrying */
- if (g_supplicant_interface_enable_selected_network(interface,
- FALSE) != 0)
- DBG("Could not disable selected network");
-
connman_network_set_connected(network, false);
connman_network_set_associating(network, false);
wifi->disconnecting = false;
--
2.7.0.rc3.207.g0ac5344
4 years, 9 months
[PATCH] Supporting wifi load balancing and band steering
by naveen@nestlabs.com
From: Naveen Singh <nasingh(a)google.com>
Enterprise APS sometimes refuse association with assoc response
status code 17. AP basically wants to steer client to a right
band or a better AP for load balancing purposes. This does not
use to work as connman has no way to know that association was
denied and it would treat this disconnect notification as a normal
disconnect. wpa supplicant was sending DisconnectReason on DBUS as
a part of PropertyChanged signal but there was no AssocStatusCode.
In this commit id of hostapd (c7fb678f3109e62af1ef39be9b12bf8370c35bde)
wpa supplicant is also sending assoc status code as a part of
PropertyChanged DBUS signal. Idea is that on a disconnect notification
from wpa supplicant, if the prior interface state is associating
(means a conection is underway) and association was denied with status
code 17 then do not proceed. This would let wpa_supplicant chose another
BSSID where association would stick.
This is been tested by running a stress test which tries connection with
an enterprise AP which frequently denies association with status code 17.
---
gsupplicant/gsupplicant.h | 2 ++
gsupplicant/supplicant.c | 19 ++++++++++++++++++-
plugins/wifi.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index a2a7605..2f9806e 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -353,6 +353,8 @@ struct _GSupplicantCallbacks {
GSupplicantPeerState state);
void (*peer_request) (GSupplicantPeer *peer);
void (*debug) (const char *str);
+ void (*update_disconnect_reasoncode)(GSupplicantInterface *interface, int reasoncode);
+ void (*update_assoc_status_code)(GSupplicantInterface *interface, int reasoncode);
};
typedef struct _GSupplicantCallbacks GSupplicantCallbacks;
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index c8fbef6..a5195b1 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -2135,9 +2135,26 @@ static void interface_property(const char *key, DBusMessageIter *iter,
} else if (g_strcmp0(key, "Networks") == 0) {
supplicant_dbus_array_foreach(iter, interface_network_added,
interface);
- } else
+ } else if (g_strcmp0(key, "DisconnectReason") == 0) {
+ int reason;
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
+ dbus_message_iter_get_basic(iter, &reason);
+ if (callbacks_pointer && callbacks_pointer->update_disconnect_reasoncode && reason != 0) {
+ callbacks_pointer->update_disconnect_reasoncode(interface, reason);
+ }
+ }
+ } else if (g_strcmp0(key, "AssocStatusCode") == 0) {
+ int status_code;
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
+ dbus_message_iter_get_basic(iter, &status_code);
+ if (callbacks_pointer && callbacks_pointer->update_assoc_status_code) {
+ callbacks_pointer->update_assoc_status_code(interface, status_code);
+ }
+ }
+ } else {
SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
+ }
}
static void scan_network_update(DBusMessageIter *iter, void *user_data)
diff --git a/plugins/wifi.c b/plugins/wifi.c
index bb1cabc..6219b81 100644
--- a/plugins/wifi.c
+++ b/plugins/wifi.c
@@ -71,6 +71,8 @@
#define P2P_LISTEN_PERIOD 500
#define P2P_LISTEN_INTERVAL 2000
+#define GSUP_80211_ASSOC_STATUS_NO_ADDITIONAL_CLIENT 17
+#define WPA_SUP_LOAD_SHAPING_MAX_RETRIES 3
static struct connman_technology *wifi_technology = NULL;
static struct connman_technology *p2p_technology = NULL;
@@ -128,6 +130,7 @@ struct wifi_data {
unsigned flags;
unsigned int watch;
int retries;
+ int wpa_sup_load_shaping_retries;
struct hidden_params *hidden;
bool postpone_hidden;
struct wifi_tethering_info *tethering_param;
@@ -144,6 +147,8 @@ struct wifi_data {
bool p2p_connecting;
bool p2p_device;
int servicing;
+ int disconnect_reasoncode;
+ int assoc_statuscode;
};
static GList *iface_list = NULL;
@@ -2291,6 +2296,19 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
return true;
}
+static bool handle_assoc_status_code(GSupplicantInterface *interface,
+ struct wifi_data *wifi)
+{
+ if (wifi->state == G_SUPPLICANT_STATE_ASSOCIATING &&
+ wifi->assoc_statuscode == GSUP_80211_ASSOC_STATUS_NO_ADDITIONAL_CLIENT &&
+ wifi->wpa_sup_load_shaping_retries < WPA_SUP_LOAD_SHAPING_MAX_RETRIES) {
+ wifi->wpa_sup_load_shaping_retries ++;
+ return TRUE;
+ }
+ wifi->wpa_sup_load_shaping_retries = 0;
+ return FALSE;
+}
+
static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
struct connman_network *network,
struct wifi_data *wifi)
@@ -2382,6 +2400,10 @@ static void interface_state(GSupplicantInterface *interface)
break;
connman_network_set_connected(network, true);
+
+ wifi->disconnect_reasoncode = 0;
+ wifi->assoc_statuscode = 0;
+ wifi->wpa_sup_load_shaping_retries = 0;
break;
case G_SUPPLICANT_STATE_DISCONNECTED:
@@ -2399,6 +2421,9 @@ static void interface_state(GSupplicantInterface *interface)
if (is_idle(wifi))
break;
+ if (handle_assoc_status_code(interface, wifi))
+ break;
+
/* If previous state was 4way-handshake, then
* it's either: psk was incorrect and thus we retry
* or if we reach the maximum retries we declare the
@@ -2935,6 +2960,24 @@ static void debug(const char *str)
connman_debug("%s", str);
}
+static void wifi_disconnect_reasoncode(GSupplicantInterface *interface, int reasoncode)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ if (wifi != NULL) {
+ wifi->disconnect_reasoncode = reasoncode;
+ }
+}
+
+static void wifi_assoc_status_code(GSupplicantInterface *interface, int status_code)
+{
+ struct wifi_data *wifi = g_supplicant_interface_get_data(interface);
+
+ if (wifi != NULL) {
+ wifi->assoc_statuscode = status_code;
+ }
+}
+
static const GSupplicantCallbacks callbacks = {
.system_ready = system_ready,
.system_killed = system_killed,
@@ -2953,6 +2996,8 @@ static const GSupplicantCallbacks callbacks = {
.peer_changed = peer_changed,
.peer_request = peer_request,
.debug = debug,
+ .update_disconnect_reasoncode = wifi_disconnect_reasoncode,
+ .update_assoc_status_code = wifi_assoc_status_code,
};
--
2.7.0.rc3.207.g0ac5344
4 years, 9 months
[PATCH v3] gsupplicant: Optimize AddNetwork Handler by avoiding DBUS call.
by naveen@nestlabs.com
From: Naveen Singh <nasingh(a)google.com>
In case network path is not NULL, network should only be removed
if the new network (to be added) is different from what is sitting
in wpa_supplicant. This would avoid two DBUS calls: AddNetwork and
SelectNetwork.
---
gsupplicant/supplicant.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index c8fbef6..4297557 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -181,6 +181,7 @@ struct _GSupplicantInterface {
GHashTable *bss_mapping;
void *data;
const char *pending_peer_path;
+ char * added_ssid;
};
struct g_supplicant_bss {
@@ -616,6 +617,7 @@ static void remove_interface(gpointer data)
g_free(interface->wps_cred.key);
g_free(interface->path);
g_free(interface->network_path);
+ g_free(interface->added_ssid);
g_free(interface->ifname);
g_free(interface->driver);
g_free(interface->bridge);
@@ -4111,6 +4113,9 @@ static void interface_add_network_result(const char *error,
interface->network_path = g_strdup(path);
+ g_free(interface->added_ssid);
+ interface->added_ssid = g_strdup(data->ssid->ssid);
+
supplicant_dbus_method_call(data->interface->path,
SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
interface_select_network_params,
@@ -4708,6 +4713,17 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
g_free(data->path);
dbus_free(data);
+ /* If this add network is for the same SSID for which
+ * wpa_supplicant already has a profile then do not need
+ * to add another profile. Only if the profile that needs
+ * to get added is different from what is there in wpa_s
+ * delete the current one. interface->added_ssid is populated
+ * once add network request is successful.*/
+
+ if (g_strcmp0(interface->added_ssid, ssid->ssid) == 0) {
+ return -EALREADY;
+ }
+
intf_data = dbus_malloc0(sizeof(*intf_data));
if (!intf_data)
return -ENOMEM;
@@ -4756,6 +4772,9 @@ static void network_remove_result(const char *error,
g_free(data->interface->network_path);
data->interface->network_path = NULL;
+ g_free(data->interface->added_ssid);
+ data->interface->added_ssid = NULL;
+
if (data->network_remove_in_progress == TRUE) {
data->network_remove_in_progress = FALSE;
connect_data = dbus_malloc0(sizeof(*connect_data));
--
2.8.0.rc3.226.g39d4020
4 years, 9 months
[PATCH] bluetooth: Remove Bluez 4.x support
by Patrik Flykt
Remove Bluez 4.x support as the 4.x versions have been discontinued
for quite some time already. Bluez 5.x versions have been supported
since ConnMan 1.11 and are actively maintained.
---
Makefile.plugins | 2 -
plugins/bluetooth_legacy.c | 1385 --------------------------------------------
2 files changed, 1387 deletions(-)
delete mode 100644 plugins/bluetooth_legacy.c
diff --git a/Makefile.plugins b/Makefile.plugins
index e90ad19..b01fd80 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -27,8 +27,6 @@ builtin_sources += plugins/wifi.c $(gsupplicant_sources)
endif
if BLUETOOTH
-builtin_modules += bluetooth_legacy
-builtin_sources += plugins/bluetooth_legacy.c
builtin_modules += bluetooth
builtin_sources += plugins/bluetooth.c
endif
diff --git a/plugins/bluetooth_legacy.c b/plugins/bluetooth_legacy.c
deleted file mode 100644
index 2d7a9e0..0000000
--- a/plugins/bluetooth_legacy.c
+++ /dev/null
@@ -1,1385 +0,0 @@
-/*
- *
- * Connection Manager
- *
- * Copyright (C) 2007-2013 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 <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <netinet/ether.h>
-
-#include <gdbus.h>
-
-#define CONNMAN_API_SUBJECT_TO_CHANGE
-#include <connman/plugin.h>
-#include <connman/technology.h>
-#include <connman/device.h>
-#include <connman/inet.h>
-#include <connman/dbus.h>
-#include <connman/log.h>
-
-#define BLUEZ_SERVICE "org.bluez"
-#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
-#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
-#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
-#define BLUEZ_NETWORK_INTERFACE BLUEZ_SERVICE ".Network"
-#define BLUEZ_NETWORK_SERVER BLUEZ_SERVICE ".NetworkServer"
-
-#define LIST_ADAPTERS "ListAdapters"
-#define ADAPTER_ADDED "AdapterAdded"
-#define ADAPTER_REMOVED "AdapterRemoved"
-#define DEVICE_REMOVED "DeviceRemoved"
-
-#define PROPERTY_CHANGED "PropertyChanged"
-#define GET_PROPERTIES "GetProperties"
-#define SET_PROPERTY "SetProperty"
-
-#define CONNECT "Connect"
-#define DISCONNECT "Disconnect"
-
-#define REGISTER "Register"
-#define UNREGISTER "Unregister"
-
-#define UUID_NAP "00001116-0000-1000-8000-00805f9b34fb"
-
-#define TIMEOUT 60000
-
-static DBusConnection *connection;
-
-static GHashTable *bluetooth_devices = NULL;
-static GHashTable *bluetooth_networks = NULL;
-static GHashTable *pending_networks = NULL;
-
-static int pan_probe(struct connman_network *network)
-{
- GHashTableIter iter;
- gpointer key, val;
-
- g_hash_table_iter_init(&iter, bluetooth_networks);
- while (g_hash_table_iter_next(&iter, &key, &val)) {
- struct connman_network *known = val;
-
- if (network != known)
- continue;
-
- DBG("network %p", network);
-
- return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-static void pan_remove(struct connman_network *network)
-{
- DBG("network %p", network);
-}
-
-static void connect_reply(DBusPendingCall *call, void *user_data)
-{
- char *path = user_data;
- struct connman_network *network;
- DBusMessage *reply;
- DBusError error;
- const char *interface = NULL;
- int index;
-
- network = g_hash_table_lookup(bluetooth_networks, path);
- if (!network)
- return;
-
- DBG("network %p", network);
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
-
- goto err;
- }
-
- if (!dbus_message_get_args(reply, &error, DBUS_TYPE_STRING,
- &interface, DBUS_TYPE_INVALID)) {
- if (dbus_error_is_set(&error)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- } else
- connman_error("Wrong arguments for connect");
- goto err;
- }
-
- if (!interface)
- goto err;
-
- DBG("interface %s", interface);
-
- index = connman_inet_ifindex(interface);
-
- connman_network_set_index(network, index);
-
- connman_network_set_connected(network, true);
-
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-
- return;
-err:
-
- connman_network_set_connected(network, false);
-
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-}
-
-static int pan_connect(struct connman_network *network)
-{
- const char *path = connman_network_get_string(network, "Path");
- const char *uuid = "nap";
- DBusMessage *message;
- DBusPendingCall *call;
-
- DBG("network %p", network);
-
- if (!path)
- return -EINVAL;
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
- BLUEZ_NETWORK_INTERFACE, CONNECT);
- if (!message)
- return -ENOMEM;
-
- dbus_message_set_auto_start(message, FALSE);
-
- dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
- DBUS_TYPE_INVALID);
-
- if (!dbus_connection_send_with_reply(connection, message,
- &call, TIMEOUT * 10)) {
- connman_error("Failed to connect service");
- dbus_message_unref(message);
- return -EINVAL;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- dbus_message_unref(message);
- return -EINVAL;
- }
-
- dbus_pending_call_set_notify(call, connect_reply, g_strdup(path),
- g_free);
-
- dbus_message_unref(message);
-
- return -EINPROGRESS;
-}
-
-static void disconnect_reply(DBusPendingCall *call, void *user_data)
-{
- char *path = user_data;
- struct connman_network *network;
- DBusMessage *reply;
- DBusError error;
-
- network = g_hash_table_lookup(bluetooth_networks, path);
- if (!network)
- return;
-
- DBG("network %p", network);
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- goto done;
- }
-
- if (!dbus_message_get_args(reply, &error, DBUS_TYPE_INVALID)) {
- if (dbus_error_is_set(&error)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- } else
- connman_error("Wrong arguments for disconnect");
- goto done;
- }
-
- connman_network_set_connected(network, false);
-
-done:
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-
- connman_network_unref(network);
-}
-
-static int pan_disconnect(struct connman_network *network)
-{
- const char *path = connman_network_get_string(network, "Path");
- DBusMessage *message;
- DBusPendingCall *call;
-
- DBG("network %p", network);
-
- if (!path)
- return -EINVAL;
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
- BLUEZ_NETWORK_INTERFACE, DISCONNECT);
- if (!message)
- return -ENOMEM;
-
- dbus_message_set_auto_start(message, FALSE);
-
- dbus_message_append_args(message, DBUS_TYPE_INVALID);
-
- if (!dbus_connection_send_with_reply(connection, message,
- &call, TIMEOUT)) {
- connman_error("Failed to disconnect service");
- dbus_message_unref(message);
- return -EINVAL;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- dbus_message_unref(message);
- return -EINVAL;
- }
-
- connman_network_ref(network);
-
- connman_network_set_associating(network, false);
-
- dbus_pending_call_set_notify(call, disconnect_reply, g_strdup(path),
- g_free);
-
- dbus_message_unref(message);
-
- return 0;
-}
-
-static struct connman_network_driver pan_driver = {
- .name = "bluetooth_legacy-pan",
- .type = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
- .priority = CONNMAN_NETWORK_PRIORITY_LOW,
- .probe = pan_probe,
- .remove = pan_remove,
- .connect = pan_connect,
- .disconnect = pan_disconnect,
-};
-
-static gboolean network_changed(DBusConnection *conn,
- DBusMessage *message, void *user_data)
-{
- const char *path = dbus_message_get_path(message);
- struct connman_network *network;
- DBusMessageIter iter, value;
- const char *key;
-
- DBG("path %s", path);
-
- network = g_hash_table_lookup(bluetooth_networks, path);
- if (!network)
- return TRUE;
-
- if (!dbus_message_iter_init(message, &iter))
- return TRUE;
-
- dbus_message_iter_get_basic(&iter, &key);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &value);
-
- if (g_str_equal(key, "Connected")) {
- dbus_bool_t connected;
-
- dbus_message_iter_get_basic(&value, &connected);
-
- if (connected)
- return TRUE;
-
- connman_network_set_associating(network, false);
- connman_network_set_connected(network, false);
- }
-
- return TRUE;
-}
-
-static void extract_properties(DBusMessage *reply, const char **parent,
- const char **address,
- const char **name,
- const char **alias,
- dbus_bool_t *powered,
- dbus_bool_t *scanning,
- DBusMessageIter *uuids,
- DBusMessageIter *networks)
-{
- DBusMessageIter array, dict;
-
- if (!dbus_message_iter_init(reply, &array))
- return;
-
- if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(&array, &dict);
-
- while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
- DBusMessageIter entry, value;
- const char *key;
-
- dbus_message_iter_recurse(&dict, &entry);
- dbus_message_iter_get_basic(&entry, &key);
-
- dbus_message_iter_next(&entry);
- dbus_message_iter_recurse(&entry, &value);
-
- if (g_str_equal(key, "Adapter")) {
- if (parent)
- dbus_message_iter_get_basic(&value, parent);
- } else if (g_str_equal(key, "Address")) {
- if (address)
- dbus_message_iter_get_basic(&value, address);
- } else if (g_str_equal(key, "Name")) {
- if (name)
- dbus_message_iter_get_basic(&value, name);
- } else if (g_str_equal(key, "Alias")) {
- if (alias)
- dbus_message_iter_get_basic(&value, alias);
- } else if (g_str_equal(key, "Powered")) {
- if (powered)
- dbus_message_iter_get_basic(&value, powered);
- } else if (g_str_equal(key, "Discovering")) {
- if (scanning)
- dbus_message_iter_get_basic(&value, scanning);
- } else if (g_str_equal(key, "Devices")) {
- if (networks)
- memcpy(networks, &value, sizeof(value));
- } else if (g_str_equal(key, "UUIDs")) {
- if (uuids)
- memcpy(uuids, &value, sizeof(value));
- }
-
- dbus_message_iter_next(&dict);
- }
-}
-
-static dbus_bool_t has_pan(DBusMessageIter *array)
-{
- DBusMessageIter value;
-
- if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
- return FALSE;
-
- dbus_message_iter_recurse(array, &value);
-
- while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
- const char *uuid;
-
- dbus_message_iter_get_basic(&value, &uuid);
-
- if (g_strcmp0(uuid, UUID_NAP) == 0)
- return TRUE;
-
- dbus_message_iter_next(&value);
- }
-
- return FALSE;
-}
-
-static void network_properties_reply(DBusPendingCall *call, void *user_data)
-{
- char *path = user_data;
- struct connman_device *device;
- struct connman_network *network;
- DBusMessage *reply;
- DBusMessageIter uuids;
- const char *parent = NULL, *address = NULL, *name = NULL;
- struct ether_addr addr;
- char ident[13];
-
- reply = dbus_pending_call_steal_reply(call);
-
- extract_properties(reply, &parent, &address, NULL, &name,
- NULL, NULL, &uuids, NULL);
-
- if (!parent)
- goto done;
-
- device = g_hash_table_lookup(bluetooth_devices, parent);
- if (!device)
- goto done;
-
- if (!address)
- goto done;
-
- ether_aton_r(address, &addr);
-
- snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
- addr.ether_addr_octet[0],
- addr.ether_addr_octet[1],
- addr.ether_addr_octet[2],
- addr.ether_addr_octet[3],
- addr.ether_addr_octet[4],
- addr.ether_addr_octet[5]);
-
- if (!has_pan(&uuids))
- goto done;
-
- network = connman_device_get_network(device, ident);
- if (network)
- goto done;
-
- network = connman_network_create(ident,
- CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN);
- if (!network)
- goto done;
-
- connman_network_set_string(network, "Path", path);
-
- connman_network_set_name(network, name);
-
- g_hash_table_replace(bluetooth_networks, g_strdup(path), network);
-
- connman_device_add_network(device, network);
-
- connman_network_set_group(network, ident);
-
-done:
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-}
-
-static void add_network(const char *path)
-{
- DBusMessage *message;
- DBusPendingCall *call;
-
- DBG("path %s", path);
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
- BLUEZ_DEVICE_INTERFACE, GET_PROPERTIES);
- if (!message)
- return;
-
- dbus_message_set_auto_start(message, FALSE);
-
- if (!dbus_connection_send_with_reply(connection, message,
- &call, TIMEOUT)) {
- connman_error("Failed to get network properties for %s", path);
- goto done;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- goto done;
- }
-
- dbus_pending_call_set_notify(call, network_properties_reply,
- g_strdup(path), g_free);
-
-done:
- dbus_message_unref(message);
-}
-
-static void check_networks(DBusMessageIter *array)
-{
- DBusMessageIter value;
-
- if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(array, &value);
-
- while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
- const char *path;
-
- dbus_message_iter_get_basic(&value, &path);
-
- add_network(path);
-
- dbus_message_iter_next(&value);
- }
-}
-
-static void check_pending_networks(const char *adapter)
-{
- GSList *networks, *list;
-
- networks = g_hash_table_lookup(pending_networks, adapter);
- if (!networks)
- return;
-
- for (list = networks; list; list = list->next) {
- char *path = list->data;
-
- add_network(path);
- }
-
- g_hash_table_remove(pending_networks, adapter);
-}
-
-static gboolean adapter_changed(DBusConnection *conn,
- DBusMessage *message, void *user_data)
-{
- const char *path = dbus_message_get_path(message);
- struct connman_device *device;
- DBusMessageIter iter, value;
- const char *key;
-
- DBG("path %s", path);
-
- device = g_hash_table_lookup(bluetooth_devices, path);
- if (!device)
- return TRUE;
-
- if (!dbus_message_iter_init(message, &iter))
- return TRUE;
-
- dbus_message_iter_get_basic(&iter, &key);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &value);
-
- if (g_str_equal(key, "Powered")) {
- dbus_bool_t val;
-
- dbus_message_iter_get_basic(&value, &val);
- connman_device_set_powered(device, val);
- if (val)
- check_pending_networks(path);
- } else if (g_str_equal(key, "Discovering")) {
- dbus_bool_t val;
-
- dbus_message_iter_get_basic(&value, &val);
- connman_device_set_scanning(device,
- CONNMAN_SERVICE_TYPE_BLUETOOTH, val);
- } else if (g_str_equal(key, "Devices")) {
- check_networks(&value);
- }
-
- return TRUE;
-}
-
-static gboolean device_removed(DBusConnection *conn,
- DBusMessage *message, void *user_data)
-{
- const char *network_path;
- struct connman_network *network;
- struct connman_device *device;
- DBusMessageIter iter;
-
- DBG("");
-
- if (!dbus_message_iter_init(message, &iter))
- return TRUE;
-
- dbus_message_iter_get_basic(&iter, &network_path);
-
- network = g_hash_table_lookup(bluetooth_networks, network_path);
- if (!network)
- return TRUE;
-
- device = connman_network_get_device(network);
- if (!device)
- return TRUE;
-
- g_hash_table_remove(bluetooth_networks, network_path);
-
- return TRUE;
-}
-
-static gboolean device_changed(DBusConnection *conn,
- DBusMessage *message, void *user_data)
-{
- const char *path = dbus_message_get_path(message);
- DBusMessageIter iter, value;
- const char *key;
-
- DBG("path %s", path);
-
- if (!dbus_message_iter_init(message, &iter))
- return TRUE;
-
- dbus_message_iter_get_basic(&iter, &key);
-
- dbus_message_iter_next(&iter);
- dbus_message_iter_recurse(&iter, &value);
-
- DBG("key %s", key);
-
- if (g_str_equal(key, "UUIDs"))
- add_network(path);
-
- return TRUE;
-}
-
-static void remove_device_networks(struct connman_device *device)
-{
- GHashTableIter iter;
- gpointer key, value;
- GSList *key_list = NULL;
- GSList *list;
-
- if (!bluetooth_networks)
- return;
-
- g_hash_table_iter_init(&iter, bluetooth_networks);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- struct connman_network *network = value;
-
- if (connman_network_get_device(network) != device)
- continue;
-
- key_list = g_slist_prepend(key_list, key);
- }
-
- for (list = key_list; list; list = list->next) {
- const char *network_path = list->data;
-
- g_hash_table_remove(bluetooth_networks, network_path);
- }
-
- g_slist_free(key_list);
-}
-
-static void add_pending_networks(const char *adapter, DBusMessageIter *array)
-{
- DBusMessageIter value;
- GSList *list = NULL;
-
- if (dbus_message_iter_get_arg_type(array) != DBUS_TYPE_ARRAY)
- return;
-
- dbus_message_iter_recurse(array, &value);
-
- while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
- const char *path;
-
- dbus_message_iter_get_basic(&value, &path);
-
- list = g_slist_prepend(list, g_strdup(path));
-
- dbus_message_iter_next(&value);
- }
-
- if (!list)
- return;
-
- g_hash_table_replace(pending_networks, g_strdup(adapter), list);
-}
-
-static void adapter_properties_reply(DBusPendingCall *call, void *user_data)
-{
- char *path = user_data;
- struct connman_device *device;
- DBusMessage *reply;
- DBusMessageIter networks;
- const char *address = NULL, *name = NULL;
- dbus_bool_t powered = FALSE, scanning = FALSE;
- struct ether_addr addr;
- char ident[13];
-
- DBG("path %s", path);
-
- reply = dbus_pending_call_steal_reply(call);
-
- if (!path)
- goto done;
-
- extract_properties(reply, NULL, &address, &name, NULL,
- &powered, &scanning, NULL, &networks);
-
- if (!address)
- goto done;
-
- if (g_strcmp0(address, "00:00:00:00:00:00") == 0)
- goto done;
-
- device = g_hash_table_lookup(bluetooth_devices, path);
- if (device)
- goto update;
-
- ether_aton_r(address, &addr);
-
- snprintf(ident, 13, "%02x%02x%02x%02x%02x%02x",
- addr.ether_addr_octet[0],
- addr.ether_addr_octet[1],
- addr.ether_addr_octet[2],
- addr.ether_addr_octet[3],
- addr.ether_addr_octet[4],
- addr.ether_addr_octet[5]);
-
- device = connman_device_create("bluetooth_legacy",
- CONNMAN_DEVICE_TYPE_BLUETOOTH);
- if (!device)
- goto done;
-
- g_hash_table_insert(bluetooth_devices, g_strdup(path), device);
-
- connman_device_set_ident(device, ident);
-
- connman_device_set_string(device, "Path", path);
-
- if (connman_device_register(device) < 0) {
- connman_device_unref(device);
- g_hash_table_remove(bluetooth_devices, path);
- goto done;
- }
-
-update:
- connman_device_set_string(device, "Address", address);
- connman_device_set_string(device, "Name", name);
- connman_device_set_string(device, "Path", path);
-
- connman_device_set_powered(device, powered);
- connman_device_set_scanning(device,
- CONNMAN_SERVICE_TYPE_BLUETOOTH, scanning);
-
- if (!powered) {
- remove_device_networks(device);
- add_pending_networks(path, &networks);
- } else
- check_networks(&networks);
-
-done:
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-}
-
-static void add_adapter(DBusConnection *conn, const char *path)
-{
- DBusMessage *message;
- DBusPendingCall *call;
-
- DBG("path %s", path);
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
- BLUEZ_ADAPTER_INTERFACE, GET_PROPERTIES);
- if (!message)
- return;
-
- dbus_message_set_auto_start(message, FALSE);
-
- if (!dbus_connection_send_with_reply(conn, message, &call, TIMEOUT)) {
- connman_error("Failed to get adapter properties for %s", path);
- goto done;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- goto done;
- }
-
- dbus_pending_call_set_notify(call, adapter_properties_reply,
- g_strdup(path), g_free);
-
-done:
- dbus_message_unref(message);
-}
-
-static gboolean adapter_added(DBusConnection *conn, DBusMessage *message,
- void *user_data)
-{
- const char *path;
-
- dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- add_adapter(conn, path);
- return TRUE;
-}
-
-static void remove_adapter(DBusConnection *conn, const char *path)
-{
- DBG("path %s", path);
-
- g_hash_table_remove(bluetooth_devices, path);
- g_hash_table_remove(pending_networks, path);
-}
-
-static gboolean adapter_removed(DBusConnection *conn, DBusMessage *message,
- void *user_data)
-{
- const char *path;
-
- dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID);
- remove_adapter(conn, path);
- return TRUE;
-}
-
-static void list_adapters_reply(DBusPendingCall *call, void *user_data)
-{
- DBusMessage *reply;
- DBusError error;
- char **adapters;
- int i, num_adapters;
-
- DBG("");
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- goto done;
- }
-
- if (!dbus_message_get_args(reply, &error, DBUS_TYPE_ARRAY,
- DBUS_TYPE_OBJECT_PATH, &adapters,
- &num_adapters, DBUS_TYPE_INVALID)) {
- if (dbus_error_is_set(&error)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- } else
- connman_error("Wrong arguments for adapter list");
- goto done;
- }
-
- for (i = 0; i < num_adapters; i++)
- add_adapter(connection, adapters[i]);
-
- g_strfreev(adapters);
-
-done:
- dbus_message_unref(reply);
-
- dbus_pending_call_unref(call);
-}
-
-static void unregister_device(gpointer data)
-{
- struct connman_device *device = data;
-
- DBG("");
-
- remove_device_networks(device);
-
- connman_device_unregister(device);
- connman_device_unref(device);
-}
-
-static void remove_network(gpointer data)
-{
- struct connman_network *network = data;
- struct connman_device *device;
-
- DBG("network %p", network);
-
- device = connman_network_get_device(network);
- if (device)
- connman_device_remove_network(device, network);
-
- connman_network_unref(network);
-}
-
-static void remove_pending_networks(gpointer data)
-{
- GSList *list = data;
-
- g_slist_free_full(list, g_free);
-}
-
-static void bluetooth_connect(DBusConnection *conn, void *user_data)
-{
- DBusMessage *message;
- DBusPendingCall *call;
-
- DBG("connection %p", conn);
-
- bluetooth_devices = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, unregister_device);
-
- bluetooth_networks = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, remove_network);
-
- pending_networks = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, remove_pending_networks);
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, "/",
- BLUEZ_MANAGER_INTERFACE, LIST_ADAPTERS);
- if (!message)
- return;
-
- dbus_message_set_auto_start(message, FALSE);
-
- if (!dbus_connection_send_with_reply(conn, message, &call, TIMEOUT)) {
- connman_error("Failed to get Bluetooth adapters");
- goto done;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- goto done;
- }
-
- dbus_pending_call_set_notify(call, list_adapters_reply, NULL, NULL);
-
-done:
- dbus_message_unref(message);
-}
-
-static void bluetooth_disconnect(DBusConnection *conn, void *user_data)
-{
- DBG("connection %p", conn);
-
- if (!bluetooth_devices)
- return;
-
- g_hash_table_destroy(bluetooth_networks);
- bluetooth_networks = NULL;
- g_hash_table_destroy(bluetooth_devices);
- bluetooth_devices = NULL;
- g_hash_table_destroy(pending_networks);
- pending_networks = NULL;
-}
-
-static int bluetooth_probe(struct connman_device *device)
-{
- GHashTableIter iter;
- gpointer key, value;
-
- DBG("device %p", device);
-
- if (!bluetooth_devices)
- return -ENOTSUP;
-
- g_hash_table_iter_init(&iter, bluetooth_devices);
-
- while (g_hash_table_iter_next(&iter, &key, &value)) {
- struct connman_device *device_pan = value;
-
- if (device == device_pan)
- return 0;
- }
-
- return -ENOTSUP;
-}
-
-static void bluetooth_remove(struct connman_device *device)
-{
- DBG("device %p", device);
-}
-
-static void powered_reply(DBusPendingCall *call, void *user_data)
-{
- DBusError error;
- DBusMessage *reply;
-
- DBG("");
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
- return;
- }
-
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-
- add_adapter(connection, user_data);
-}
-
-static int change_powered(DBusConnection *conn, const char *path,
- dbus_bool_t powered)
-{
- DBusMessage *message;
- DBusMessageIter iter;
- DBusPendingCall *call;
-
- DBG("");
-
- if (!path)
- return -EINVAL;
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
- BLUEZ_ADAPTER_INTERFACE, SET_PROPERTY);
- if (!message)
- return -ENOMEM;
-
- dbus_message_set_auto_start(message, FALSE);
-
- dbus_message_iter_init_append(message, &iter);
- connman_dbus_property_append_basic(&iter, "Powered",
- DBUS_TYPE_BOOLEAN, &powered);
-
- if (!dbus_connection_send_with_reply(conn, message, &call, TIMEOUT)) {
- connman_error("Failed to change Powered property");
- dbus_message_unref(message);
- return -EINVAL;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- dbus_message_unref(message);
- return -EINVAL;
- }
-
- dbus_pending_call_set_notify(call, powered_reply,
- g_strdup(path), g_free);
-
- dbus_message_unref(message);
-
- return -EINPROGRESS;
-}
-
-static int bluetooth_enable(struct connman_device *device)
-{
- const char *path = connman_device_get_string(device, "Path");
-
- DBG("device %p", device);
-
- return change_powered(connection, path, TRUE);
-}
-
-static int bluetooth_disable(struct connman_device *device)
-{
- const char *path = connman_device_get_string(device, "Path");
-
- DBG("device %p", device);
-
- return change_powered(connection, path, FALSE);
-}
-
-static struct connman_device_driver bluetooth_driver = {
- .name = "bluetooth_legacy",
- .type = CONNMAN_DEVICE_TYPE_BLUETOOTH,
- .probe = bluetooth_probe,
- .remove = bluetooth_remove,
- .enable = bluetooth_enable,
- .disable = bluetooth_disable,
-};
-
-static int tech_probe(struct connman_technology *technology)
-{
- return 0;
-}
-
-static void tech_remove(struct connman_technology *technology)
-{
-}
-
-static void server_register_reply(DBusPendingCall *call, void *user_data)
-{
- struct connman_technology *technology = user_data;
- DBusError error;
- DBusMessage *reply;
-
- DBG("");
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
- return;
- }
-
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-
- connman_technology_tethering_notify(technology, true);
-}
-
-static void server_unregister_reply(DBusPendingCall *call, void *user_data)
-{
- struct connman_technology *technology = user_data;
- DBusError error;
- DBusMessage *reply;
-
- DBG("");
-
- reply = dbus_pending_call_steal_reply(call);
-
- dbus_error_init(&error);
-
- if (dbus_set_error_from_message(&error, reply)) {
- connman_error("%s", error.message);
- dbus_error_free(&error);
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
- return;
- }
-
- dbus_message_unref(reply);
- dbus_pending_call_unref(call);
-
- connman_technology_tethering_notify(technology, false);
-}
-
-
-static void server_register(const char *path, const char *uuid,
- struct connman_technology *technology,
- const char *bridge, bool enabled)
-{
- DBusMessage *message;
- DBusPendingCall *call;
- char *command;
-
- DBG("path %s enabled %d", path, enabled);
-
- command = enabled ? REGISTER : UNREGISTER;
-
- message = dbus_message_new_method_call(BLUEZ_SERVICE, path,
- BLUEZ_NETWORK_SERVER, command);
- if (!message)
- return;
-
- dbus_message_set_auto_start(message, FALSE);
-
- dbus_message_append_args(message, DBUS_TYPE_STRING, &uuid,
- DBUS_TYPE_INVALID);
-
- if (enabled)
- dbus_message_append_args(message, DBUS_TYPE_STRING, &bridge,
- DBUS_TYPE_INVALID);
-
- if (!dbus_connection_send_with_reply(connection, message,
- &call, TIMEOUT)) {
- connman_error("Failed to enable PAN server");
- dbus_message_unref(message);
- return;
- }
-
- if (!call) {
- connman_error("D-Bus connection not available");
- dbus_message_unref(message);
- return;
- }
-
- if (enabled)
- dbus_pending_call_set_notify(call, server_register_reply,
- technology, NULL);
- else
- dbus_pending_call_set_notify(call, server_unregister_reply,
- technology, NULL);
-
- dbus_message_unref(message);
-}
-
-struct tethering_info {
- struct connman_technology *technology;
- const char *bridge;
-};
-
-static void enable_nap(gpointer key, gpointer value, gpointer user_data)
-{
- struct tethering_info *info = user_data;
- struct connman_device *device = value;
- const char *path;
-
- DBG("");
-
- path = connman_device_get_string(device, "Path");
-
- server_register(path, "nap", info->technology, info->bridge, true);
-}
-
-static void disable_nap(gpointer key, gpointer value, gpointer user_data)
-{
- struct tethering_info *info = user_data;
- struct connman_device *device = value;
- const char *path;
-
- DBG("");
-
- path = connman_device_get_string(device, "Path");
-
- server_register(path, "nap", info->technology, info->bridge, false);
-}
-
-static int tech_set_tethering(struct connman_technology *technology,
- const char *identifier, const char *passphrase,
- const char *bridge, bool enabled)
-{
- struct tethering_info info = {
- .technology = technology,
- .bridge = bridge,
- };
-
- DBG("bridge %s", bridge);
-
- if (!bluetooth_devices)
- return -ENOTCONN;
-
- if (enabled)
- g_hash_table_foreach(bluetooth_devices, enable_nap, &info);
- else
- g_hash_table_foreach(bluetooth_devices, disable_nap, &info);
-
- return 0;
-}
-
-static struct connman_technology_driver tech_driver = {
- .name = "bluetooth_legacy",
- .type = CONNMAN_SERVICE_TYPE_BLUETOOTH,
- .priority = -10,
- .probe = tech_probe,
- .remove = tech_remove,
- .set_tethering = tech_set_tethering,
-};
-
-static guint watch;
-static guint added_watch;
-static guint removed_watch;
-static guint adapter_watch;
-static guint device_watch;
-static guint device_removed_watch;
-static guint network_watch;
-
-static int bluetooth_init(void)
-{
- int err;
-
- connection = connman_dbus_get_connection();
- if (!connection)
- return -EIO;
-
- watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
- bluetooth_connect, bluetooth_disconnect, NULL, NULL);
-
- added_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, NULL,
- BLUEZ_MANAGER_INTERFACE,
- ADAPTER_ADDED, adapter_added,
- NULL, NULL);
-
- removed_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, NULL,
- BLUEZ_MANAGER_INTERFACE,
- ADAPTER_REMOVED, adapter_removed,
- NULL, NULL);
-
- adapter_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE,
- NULL, BLUEZ_ADAPTER_INTERFACE,
- PROPERTY_CHANGED, adapter_changed,
- NULL, NULL);
-
- device_removed_watch = g_dbus_add_signal_watch(connection,
- BLUEZ_SERVICE, NULL,
- BLUEZ_ADAPTER_INTERFACE,
- DEVICE_REMOVED, device_removed,
- NULL, NULL);
-
- device_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE, NULL,
- BLUEZ_DEVICE_INTERFACE,
- PROPERTY_CHANGED, device_changed,
- NULL, NULL);
-
- network_watch = g_dbus_add_signal_watch(connection, BLUEZ_SERVICE,
- NULL, BLUEZ_NETWORK_INTERFACE,
- PROPERTY_CHANGED, network_changed,
- NULL, NULL);
-
- if (watch == 0 || added_watch == 0 || removed_watch == 0
- || adapter_watch == 0 || network_watch == 0
- || device_watch == 0
- || device_removed_watch == 0) {
- err = -EIO;
- goto remove;
- }
-
- err = connman_network_driver_register(&pan_driver);
- if (err < 0)
- goto remove;
-
- err = connman_device_driver_register(&bluetooth_driver);
- if (err < 0) {
- connman_network_driver_unregister(&pan_driver);
- goto remove;
- }
-
- err = connman_technology_driver_register(&tech_driver);
- if (err < 0) {
- connman_device_driver_unregister(&bluetooth_driver);
- connman_network_driver_unregister(&pan_driver);
- goto remove;
- }
-
- return 0;
-
-remove:
- g_dbus_remove_watch(connection, watch);
- g_dbus_remove_watch(connection, added_watch);
- g_dbus_remove_watch(connection, removed_watch);
- g_dbus_remove_watch(connection, adapter_watch);
- g_dbus_remove_watch(connection, device_removed_watch);
- g_dbus_remove_watch(connection, device_watch);
- g_dbus_remove_watch(connection, network_watch);
-
- dbus_connection_unref(connection);
-
- return err;
-}
-
-static void bluetooth_exit(void)
-{
- g_dbus_remove_watch(connection, watch);
- g_dbus_remove_watch(connection, added_watch);
- g_dbus_remove_watch(connection, removed_watch);
- g_dbus_remove_watch(connection, adapter_watch);
- g_dbus_remove_watch(connection, device_removed_watch);
- g_dbus_remove_watch(connection, device_watch);
- g_dbus_remove_watch(connection, network_watch);
-
- /*
- * We unset the disabling of the Bluetooth device when shutting down
- * so that non-PAN BT connections are not affected.
- */
- bluetooth_driver.disable = NULL;
-
- bluetooth_disconnect(connection, NULL);
-
- connman_technology_driver_unregister(&tech_driver);
-
- connman_device_driver_unregister(&bluetooth_driver);
- connman_network_driver_unregister(&pan_driver);
-
- dbus_connection_unref(connection);
-}
-
-CONNMAN_PLUGIN_DEFINE(bluetooth_legacy, "Bluetooth technology plugin (legacy)",
- VERSION, CONNMAN_PLUGIN_PRIORITY_LOW,
- bluetooth_init, bluetooth_exit)
--
2.1.4
4 years, 9 months
Manual DNS configuration with DHCP services
by Moberg, Patrik
Hello,
What is the best practise when using Connman to achieve manual configuration of DNS when using DHCP based services? The goal is to regardless of which service that is online always use a manual DNS.
With auto connect disabled, I have tried to set "Nameservers.Configuration" (via d-bus) to an IP address prior to the service being connected (connect done via d-bus as well). The service then looks ok with the proper IP address in "Nameservers" for the service. However the routing table is then unexpectedly populated. For example, the default gateway entry has destination set to IP in "Nameservers.Configuration", with gateway set to DHCP DNS IP address, and netmask 255.255.255.255.
Cheers,
Patrik Moberg
4 years, 9 months
RFC: multipath routing for services and sessions
by Dragos Tatulea
Hello,
We've been working recently on adding a few features to ConnMan for
Multipath TCP. However, most features are not related to Multipath TCP
and they could be useful in upstream. Please let me know what is of
interest from the list below:
* Per service multipath routing: This is a per service flag that
allows the installation of a multipath table for a service.
Something in the lines of:
$> ip rule
0: from all lookup local
32763: from 10.10.3.2 lookup 283
32764: from 10.10.2.2 lookup 281
32765: from 10.10.1.2 lookup 279
32766: from all lookup main
32767: from all lookup default
$> ip route show table 283
default via 10.10.3.1 dev vethc3
10.10.3.0/24 dev vethc3 scope link
There are 3 services above with multipath routing on.
There's also a generic switch to turn it on by default in all
services.
* Multipath routing support for sessions: Each session contains a list
of services that are added automatically if they have the multipath
option set and they are considered connected. For all those services,
fwmark + src ip rules are created to the service multipath routing
table. It would look like this:
$ ip rule
0: from all lookup local
32760: from 10.10.1.2 fwmark 0x10000 lookup 261
32761: from 10.10.3.2 fwmark 0x10000 lookup 265
32762: from all fwmark 0x10000 lookup 65536
32763: from 10.10.3.2 lookup 265
32764: from 10.10.2.2 lookup 263
32765: from 10.10.1.2 lookup 261
32766: from all lookup main
32767: from all lookup default
The default service is not added to this list. But it has the
default rule (32762).
It's also possible to modify the list via the DBus API.
* Flow Selectors: this is a fancy name for per session 5 tuple
iptables rules. A 5 tuple contains: source/destination ip,
protocol (tcp|udp), source/destination port. Fields can also be
omitted. 3 rules would look like this:
$ iptables -t mangle -L
...
Chain connman-OUTPUT (1 references)
target prot opt source destination
MARK tcp -- 11.11.11.11 22.22.22.22 tcp spt:1111 dpt:2222 MARK set 0x10000
MARK all -- 33.33.33.33 44.44.44.44 MARK set 0x10000
MARK udp -- anywhere anywhere udp spt:7777 dpt:8888 MARK set 0x10000
...
Currently these tules are only added to the output chain. But that can
be made more flexible.
These work as/in tandem with policy descriptors. The idea is to bind
a certain kind of traffic to a session. However, you don't necessarily
need a policy file for them. They can be set via the session API too.
Would these features be interesting for upstream ConnMan? If yes, I'd
gladly split the current patches [1] into per feature patch sets and
send them here. Please let me know.
[1] - https://github.com/endocode/connman/tree/work
Thanks
--
Dragos Tatulea
Software Developer @ Endocode AG
dragos(a)endocode.com
Endocode AG, Brückenstraße 5A, 10179 Berlin
+49 30 1206 4472 | info(a)endocode.com | www.endocode.com
Vorstandsvorsitzender: Mirko Boehm
Vorstände: Dr. Thomas Fricke, Sebastian Sucker
Aufsichtsratsvorsitzende: Alexandra Boehm
Registergericht: Amtsgericht Charlottenburg - HRB 150748 B
4 years, 10 months
[PATCH] doc: Fixed typo mistakes
by Nishant Chaprana
---
doc/agent-api.txt | 2 +-
doc/config-format.txt | 2 +-
doc/connmanctl.1.in | 2 +-
doc/counter-api.txt | 4 ++--
doc/plugin-api.txt | 6 +++---
doc/service-api.txt | 2 +-
doc/session-api.txt | 2 +-
doc/vpn-overview.txt | 2 +-
8 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/doc/agent-api.txt b/doc/agent-api.txt
index aa7271d..d357169 100644
--- a/doc/agent-api.txt
+++ b/doc/agent-api.txt
@@ -119,7 +119,7 @@ Fields string Name
string PreviousPassphrase
The previous passphrase successfully saved, i.e.
- which led to a successfull connection. This field is
+ which led to a successful connection. This field is
provided as an informational argument when connecting
with it does not work anymore, for instance when it
has been changed on the AP. Such argument appears when
diff --git a/doc/config-format.txt b/doc/config-format.txt
index eae51e0..e7089af 100644
--- a/doc/config-format.txt
+++ b/doc/config-format.txt
@@ -51,7 +51,7 @@ Allowed fields:
Example: 2001:db8::2/64/2001:db8::1
2001:db8::1:2:3:4/64
- IPv6.Privacy: IPv6 privacy option. Value can be either "disabled",
- "enabled" or "preferred" (or the misspelled "prefered"). See use_tempaddr
+ "enabled" or "preferred" (or the misspelled "preferred"). See use_tempaddr
variable description in Linux kernel Documentation/networking/ip-sysctl.txt
file.
- MAC: MAC address of the interface where this setting should be applied.
diff --git a/doc/connmanctl.1.in b/doc/connmanctl.1.in
index 0f891bd..ad2a01d 100644
--- a/doc/connmanctl.1.in
+++ b/doc/connmanctl.1.in
@@ -47,7 +47,7 @@ Shows the abbreviated help menu in the terminal.
.PP
.TP
.B state
-Shows the system properties. Includes ths online state of the
+Shows the system properties. Includes this online state of the
system, offline mode, and session mode.
.PP
.TP
diff --git a/doc/counter-api.txt b/doc/counter-api.txt
index 32411d5..c0d9b76 100644
--- a/doc/counter-api.txt
+++ b/doc/counter-api.txt
@@ -47,12 +47,12 @@ Methods void Release()
RX.Errors
- Total number of erronous packets
+ Total number of erroneous packets
received.
TX.Errors
- Total number of erronous packets
+ Total number of erroneous packets
sent.
RX.Dropped
diff --git a/doc/plugin-api.txt b/doc/plugin-api.txt
index 616938b..3ed8f2a 100644
--- a/doc/plugin-api.txt
+++ b/doc/plugin-api.txt
@@ -65,7 +65,7 @@ plugin initialization function, bluetooth_init() in this example:
connman_technology_driver_register(&tech_driver);
-In this document the error check is supressed for the sake of simplicity.
+In this document the error check is suppressed for the sake of simplicity.
All plugins should check return values in driver registration functions.
After this call ConnMan becomes aware of the new Technology plugin and will
@@ -101,7 +101,7 @@ And to register the driver:
'connman_device_driver_register()' is called during the plugin initialization
process, not necessarily at the plugin init function.
-In this document the error check is supressed for the sake of simplicity.
+In this document the error check is suppressed for the sake of simplicity.
All plugins should check return values in driver registration functions.
Additionally code to handle the detection of new devices needs to be written
@@ -147,7 +147,7 @@ And then call the register function:
connman_network_driver_register(&network_driver);
-In this document the error check is supressed for the sake of simplicity.
+In this document the error check is suppressed for the sake of simplicity.
All plugins should check return values in driver registration functions.
The next step would be the probe of a Network entity, for the bluetooth
diff --git a/doc/service-api.txt b/doc/service-api.txt
index e2e9e84..763414e 100644
--- a/doc/service-api.txt
+++ b/doc/service-api.txt
@@ -378,7 +378,7 @@ Properties string State [readonly]
enabled and system prefers to use public
addresses over temporary addresses.
- Value "prefered" means that privacy extension is
+ Value "preferred" means that privacy extension is
enabled and system prefers temporary addresses
over public addresses.
diff --git a/doc/session-api.txt b/doc/session-api.txt
index 3aac535..9e588a9 100644
--- a/doc/session-api.txt
+++ b/doc/session-api.txt
@@ -140,7 +140,7 @@ Settings string State [readonly]
The services are sorted in the order of the bearer
entries in this list.
- Also "*" matches any bearer. This is usefull to prefer
+ Also "*" matches any bearer. This is useful to prefer
certain bearers such as 'wifi' with a fallback to any
other available bearer.
diff --git a/doc/vpn-overview.txt b/doc/vpn-overview.txt
index 42b6e94..d7be919 100644
--- a/doc/vpn-overview.txt
+++ b/doc/vpn-overview.txt
@@ -54,7 +54,7 @@ is established (meaning VPN client has managed to create a connection
to VPN server), then State property is set to "ready" and PropertyChanged
signal is sent. If the connection cannot be established, then
State property is set to "failure".
-After successfull connection, the relevant connection properties are sent
+After successful connection, the relevant connection properties are sent
by PropertyChanged signal; like IPv[4|6] information, the index of the
VPN tunneling interface (if there is any), nameserver information,
server specified routes etc.
--
1.9.1
4 years, 10 months
[PATCH] iptables-unit: Fixed dereferencing null pointer in assert_rule()
by Nishant Chaprana
---
tools/iptables-unit.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/tools/iptables-unit.c b/tools/iptables-unit.c
index 9c09867..d261106 100644
--- a/tools/iptables-unit.c
+++ b/tools/iptables-unit.c
@@ -43,15 +43,14 @@ static bool assert_rule(const char *table_name, const char *rule)
for (i = 0; lines[i]; i++) {
DBG("lines[%02d]: %s\n", i, lines[i]);
- if (g_strcmp0(lines[i], rule) == 0)
- break;
+ if (g_strcmp0(lines[i], rule) == 0) {
+ g_strfreev(lines);
+ return true;
+ }
}
- g_strfreev(lines);
-
- if (!lines[i])
- return false;
- return true;
+ g_strfreev(lines);
+ return false;
}
static void assert_rule_exists(const char *table_name, const char *rule)
--
1.9.1
4 years, 10 months