Commit e9844547 authored by Jussi Laakkonen's avatar Jussi Laakkonen

[connman] Explicitly set device managed status for notifications. JB#43928

This commit changes the device status notify by removing the managed
boolean from each notify call. Instead, the managed state is to be set
explicitely for the device using connman_device_set_managed(). The
managed state can be checked with connman_device_get_managed().

When managed state changes a device status change notification is sent
without any change in the device status (no transition). This is to
indicate each registered component about the managed state change only.
When the on/off status change is done the transition is indicated
(connman_device_has_status_changed_to()). If the managed state changes
when there is no status set for the device no notification will be sent.
If status does not change connman_device_status_notify() does not
forward notify. Identical status to previous is sent only when the
managed status is changed.

Developer mode plugin sets managed state to false when a appropriate
device comes up. This state is not changed when removing the device.

Ethernet plugin is changed to ignore status changes in managed mode.
If the device is managed then only in case the device status is off
it needs to be processed in order to remove the device from list. If
there is no change and device is not managed, notify is ignored.

Similarly to ethernet plugin the firewall reacts only to non-managed
notifies with status change and in case the device is managed and is put
off.

Tests are also updated to use the new managed approach instead of
passing it along with notifies.
parent 9c7ac9f8
......@@ -111,8 +111,11 @@ struct connman_device *connman_device_create_from_index(int index);
struct connman_device *connman_device_find_by_index(int index);
int connman_device_reconnect_service(struct connman_device *device);
void connman_device_status_notify(struct connman_device *device, bool on,
bool managed);
void connman_device_set_managed(struct connman_device *device, bool managed);
bool connman_device_get_managed(struct connman_device *device);
bool connman_device_has_status_changed_to(struct connman_device *device,
bool new_status);
void connman_device_status_notify(struct connman_device *device, bool on);
struct connman_device_driver {
const char *name;
......
......@@ -58,13 +58,7 @@ struct connman_notifier {
struct connman_ipconfig *ipconfig);
void (*idle_state) (bool idle);
void (*tethering_changed) (struct connman_technology *tech, bool on);
/*
* The boolean 'on' defines device state, boolean 'managed' tells if
* connman should manage this device or not. If device is not managed it
* means that an external component brought that up.
*/
void (*device_status_changed) (struct connman_device *device, bool on,
bool managed);
void (*device_status_changed) (struct connman_device *device, bool on);
/* Placeholders for future extensions */
void (*_reserved[9])(void);
......
......@@ -446,22 +446,46 @@ static struct connman_technology_driver eth_tech_driver = {
};
static void ethernet_device_status_changed(struct connman_device *device,
bool on, bool managed)
bool on)
{
int index;
if (!device)
return;
/* This is connman device, do not add them to ignore list */
if (managed)
return;
if (connman_device_get_type(device) != CONNMAN_DEVICE_TYPE_ETHERNET)
return;
index = connman_device_get_index(device);
/* Device is managed by connman */
if (connman_device_get_managed(device)) {
/*
* If there is a status change, this is a status change
* notification from a managed device, which can be ignored.
* Otherwise when the status has not changed and transition is
* from non-managed to managed this must be processed to remove
* the device index from the list in case device is off.
*/
if (connman_device_has_status_changed_to(device, on)) {
DBG("ignoring managed status change notify");
return;
} else {
DBG("device %p is set as managed, remove from list",
device);
ignore_index_list = g_slist_remove(ignore_index_list,
GINT_TO_POINTER(index));
return;
}
} else if (!connman_device_has_status_changed_to(device, on)) {
/*
* If non-managed device has no change, it is managed true to
* false notify, which can be ignored.
*/
DBG("ignoring managed status change to false notify");
return;
}
if (on) {
DBG("add device %p", device);
......
......@@ -85,7 +85,7 @@ static const char *usb_moded_entries[] = {
enum usb_moded_service_state_t {
USB_MODED_SERVICE_UNKNOWN = 0,
USB_MODED_SERVICE_CONNECT,
USB_MODED_SERVICE_DISCONNECT
USB_MODED_SERVICE_DISCONNECT,
};
struct usb_moded_service_data {
......@@ -237,18 +237,22 @@ static bool pending_devices_remove(struct connman_device *device)
return g_hash_table_remove(pending_devices, interface);
}
static bool pending_devices_add(struct connman_device *device)
static int pending_devices_add(struct connman_device *device)
{
const char *interface;
DBG("");
if (!pending_devices || !device) {
DBG("hash table unset or no device");
return false;
if (!pending_devices) {
DBG("hash table is not set");
return -EINVAL;
}
interface = connman_device_get_string(device, "Interface");
if (!interface) {
DBG("device %p has no interface", device);
return -ENOENT;
}
DBG("add device %d %s %s", connman_device_get_index(device),
connman_device_get_ident(device), interface);
......@@ -256,11 +260,11 @@ static bool pending_devices_add(struct connman_device *device)
/* Interfaces are unique, second notification should not replace old */
if (g_hash_table_contains(pending_devices, interface)) {
DBG("interface %s already exists", interface);
return false;
return -EEXIST;
}
return g_hash_table_replace(pending_devices, g_strdup(interface),
connman_device_ref(device));
connman_device_ref(device)) ? 0 : -EEXIST;
}
......@@ -291,7 +295,7 @@ static void send_notify(struct connman_device *device, bool on)
return;
}
connman_device_status_notify(device, on, NOT_MANAGED);
connman_device_status_notify(device, on);
/* Reset the developer mode interface interface goes down */
if (!on && usb_moded_status != USB_MODED_DEVELOPER_MODE) {
......@@ -642,8 +646,19 @@ static void developer_mode_newlink(unsigned short type, int index,
return;
}
if (!pending_devices_add(device))
DBG("cannot add pending device %p", device);
switch (pending_devices_add(device)) {
case 0:
break;
case -EINVAL:
case -ENOENT:
case -EEXIST:
/* fallthrough */
DBG("no notification for device %p", device);
default:
return;
}
connman_device_set_managed(device, false);
/*
* Status check is necessary only when enabling. Notify if in developer
......@@ -671,8 +686,12 @@ static void developer_mode_dellink(unsigned short type, int index,
return;
}
/* Notify is sent if interface matches */
send_notify(device, false);
/*
* If this is a non-managed device the notify is sent if interface
* matches
*/
if (!connman_device_get_managed(device))
send_notify(device, false);
/* Interface down, remove device, not needed anymore */
if (!pending_devices_remove(device))
......
......@@ -913,7 +913,7 @@ void __connman_notifier_ipconfig_changed(struct connman_service *service,
void __connman_notifier_tethering_changed(struct connman_technology* tech,
bool on);
void __connman_notifier_device_status_changed(struct connman_device *device,
bool on, bool managed);
bool on);
bool __connman_notifier_is_connected(void);
const char *__connman_notifier_get_state(void);
......
......@@ -45,6 +45,13 @@ enum connman_pending_type {
PENDING_DISABLE = 2,
};
enum connman_device_status {
CONNMAN_DEVICE_STATUS_UNSET = -1, /* initial */
CONNMAN_DEVICE_STATUS_OFF = 0, /* false */
CONNMAN_DEVICE_STATUS_ON = 1, /* true */
};
struct connman_device {
int refcount;
enum connman_device_type type;
......@@ -69,6 +76,9 @@ struct connman_device {
char *last_network;
struct connman_network *network;
GHashTable *networks;
enum connman_device_status status;
bool managed; /* Whether this device is managed by connman or not */
};
static void clear_pending_trigger(struct connman_device *device)
......@@ -434,6 +444,8 @@ struct connman_device *connman_device_create(const char *node,
device->refcount = 1;
device->status = CONNMAN_DEVICE_STATUS_UNSET;
device->managed = true; /* By default, device is managed */
device->type = type;
device->name = g_strdup(type2description(device->type));
......@@ -668,13 +680,81 @@ int connman_device_reconnect_service(struct connman_device *device)
return 0;
}
void connman_device_status_notify(struct connman_device *device, bool on,
bool managed)
void connman_device_set_managed(struct connman_device *device, bool managed)
{
bool notify_change = false;
if (!device)
return;
__connman_notifier_device_status_changed(device, on, managed);
DBG("device %p managed: %d -> %d", device, device->managed, managed);
if (device->managed != managed)
notify_change = true;
device->managed = managed;
/*
* If there is a change in managed state and device status has been
* set notify current status. The status does not change -> no state
* transition was in place.
*/
if (notify_change) {
switch (device->status) {
case CONNMAN_DEVICE_STATUS_OFF:
case CONNMAN_DEVICE_STATUS_ON:
__connman_notifier_device_status_changed(device,
(bool)device->status);
break;
default:
break;
}
}
}
bool connman_device_get_managed(struct connman_device *device)
{
if (!device)
return true;
return device->managed;
}
bool connman_device_has_status_changed_to(struct connman_device *device,
bool new_status)
{
if (!device)
return false;
DBG("device %p status %d -> %d", device, device->status, new_status);
switch (device->status) {
case CONNMAN_DEVICE_STATUS_UNSET:
return true;
case CONNMAN_DEVICE_STATUS_OFF:
case CONNMAN_DEVICE_STATUS_ON:
return (int)new_status != device->status;
}
return false;
}
void connman_device_status_notify(struct connman_device *device, bool on)
{
if (!device)
return;
DBG("device %p on:%d managed:%d", device, on, device->managed);
if (!connman_device_has_status_changed_to(device, on)) {
DBG("state has not changed, notify is not done");
return;
}
/* Notify new state to indicate state transition */
__connman_notifier_device_status_changed(device, on);
device->status = on ? CONNMAN_DEVICE_STATUS_ON :
CONNMAN_DEVICE_STATUS_OFF;
}
static void mark_network_available(gpointer key, gpointer value,
......
......@@ -1277,8 +1277,7 @@ disable:
g_free(ifname);
}
static void device_status_changed(struct connman_device *device, bool on,
bool managed)
static void device_status_changed(struct connman_device *device, bool on)
{
struct firewall_context *ctx;
char *ifname = NULL;
......@@ -1289,7 +1288,32 @@ static void device_status_changed(struct connman_device *device, bool on,
return;
}
if (managed) {
/* Device is managed by connman */
if (connman_device_get_managed(device)) {
/*
* If there is a status change, this is a status change
* notification from a managed device, which can be ignored.
* Otherwise when the status has not changed and transition is
* from non-managed to managed this must be processed to remove
* the device index from the list in case device is off.
*/
if (connman_device_has_status_changed_to(device, on)) {
DBG("ignoring managed status change notify");
return;
} else if (on) {
DBG("ignoring managed false to true with status on");
return;
}
} else if (!connman_device_has_status_changed_to(device, on)) {
/*
* If non-managed device has no change, it is managed true to
* false notify, which can be ignored.
*/
DBG("ignoring managed status change to false notify");
return;
}
if (connman_device_get_managed(device)) {
DBG("ignoring managed device %p", device);
return;
}
......@@ -1306,7 +1330,7 @@ static void device_status_changed(struct connman_device *device, bool on,
return;
}
DBG("gadget device %s %s", ifname, on ? "up" : "down");
DBG("device %s %s", ifname, on ? "up" : "down");
ctx = g_hash_table_lookup(current_dynamic_rules, ifname);
......
......@@ -385,7 +385,7 @@ void __connman_notifier_tethering_changed(struct connman_technology* tech,
}
void __connman_notifier_device_status_changed(struct connman_device *device,
bool on, bool managed)
bool on)
{
GSList *l = notifier_list;
......@@ -394,7 +394,7 @@ void __connman_notifier_device_status_changed(struct connman_device *device,
const struct connman_notifier *notifier = l->data;
if (notifier->device_status_changed)
notifier->device_status_changed(device, on, managed);
notifier->device_status_changed(device, on);
l = next;
}
......
......@@ -377,6 +377,17 @@ enum connman_device_type connman_device_get_type(struct connman_device *device)
return 0;
}
bool connman_device_get_managed(struct connman_device *device)
{
return true;
}
bool connman_device_has_status_changed_to(struct connman_device *device,
bool new_status)
{
return true;
}
// rtnl dummies
int connman_rtnl_register(struct connman_rtnl *rtnl)
......
......@@ -1217,18 +1217,22 @@ gboolean g_file_get_contents(const gchar *filename, gchar **contents,
struct connman_device {
const char *ifname;
bool managed;
};
static struct connman_device test_device1 = {
.ifname = "rndis0",
.managed = false,
};
static struct connman_device test_device2 = {
.ifname = "usb0",
.managed = false,
};
static struct connman_device test_device3 = {
.ifname = NULL,
.managed = false,
};
const char *connman_device_get_string(struct connman_device *device,
......@@ -1240,6 +1244,29 @@ const char *connman_device_get_string(struct connman_device *device,
return NULL;
}
void connman_device_set_managed(struct connman_device *device, bool managed)
{
if (!device)
return;
device->managed = managed;
}
bool connman_device_get_managed(struct connman_device *device)
{
if (!device)
return true;
return device->managed;
}
/* TODO implement this properly */
bool connman_device_has_status_changed_to(struct connman_device *device,
bool new_status)
{
return true;
}
// End of dummies
#define CHAINS_GEN4 3
......@@ -3914,13 +3941,13 @@ static void firewall_test_device_status0()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* on */
firewall_notifier->device_status_changed(&test_device1, true, false);
firewall_notifier->device_status_changed(&test_device1, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 2);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 2);
check_rules(assert_rule_exists, 0, device_rules, test_device1.ifname);
/* off */
firewall_notifier->device_status_changed(&test_device1, false, false);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
......@@ -3949,39 +3976,39 @@ static void firewall_test_device_status1()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* device 1 on */
firewall_notifier->device_status_changed(&test_device1, true, false);
firewall_notifier->device_status_changed(&test_device1, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 2);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 2);
check_rules(assert_rule_exists, 0, device_rules, test_device1.ifname);
/* device 1 off */
firewall_notifier->device_status_changed(&test_device1, false, false);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
test_device1.ifname);
/* device 1 on */
firewall_notifier->device_status_changed(&test_device1, true, false);
firewall_notifier->device_status_changed(&test_device1, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 2);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 2);
check_rules(assert_rule_exists, 0, device_rules, test_device1.ifname);
/* device 2 on */
firewall_notifier->device_status_changed(&test_device2, true, false);
firewall_notifier->device_status_changed(&test_device2, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 4);
check_rules(assert_rule_exists, 0, device_rules, test_device2.ifname);
/* device 1 off */
firewall_notifier->device_status_changed(&test_device1, false, false);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 2);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 2);
check_rules(assert_rule_not_exists, 0, device_rules,
test_device1.ifname);
/* device 2 off */
firewall_notifier->device_status_changed(&test_device2, false, false);
firewall_notifier->device_status_changed(&test_device2, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
......@@ -4010,26 +4037,26 @@ static void firewall_test_device_status2()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* on */
firewall_notifier->device_status_changed(&test_device1, true, false);
firewall_notifier->device_status_changed(&test_device1, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 2);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 2);
check_rules(assert_rule_exists, 0, device_rules, test_device1.ifname);
/* on double */
firewall_notifier->device_status_changed(&test_device1, true, false);
firewall_notifier->device_status_changed(&test_device1, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4 + 2);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6 + 2);
check_rules(assert_rule_exists, 0, device_rules, test_device1.ifname);
/* off */
firewall_notifier->device_status_changed(&test_device1, false, false);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
test_device1.ifname);
/* off double */
firewall_notifier->device_status_changed(&test_device1, false, false);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
......@@ -4061,14 +4088,15 @@ static void firewall_test_device_status3()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* on */
firewall_notifier->device_status_changed(&test_device1, true, true);
test_device1.managed = true;
firewall_notifier->device_status_changed(&test_device1, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
test_device1.ifname);
/* off */
firewall_notifier->device_status_changed(&test_device1, false, true);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
......@@ -4081,6 +4109,8 @@ static void firewall_test_device_status3()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, 0);
__connman_iptables_cleanup();
test_device1.managed = false;
}
/* Only off notify from managed device - nothing done */
......@@ -4097,7 +4127,7 @@ static void firewall_test_device_status4()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* Managed device off notification, nothing is done */
firewall_notifier->device_status_changed(&test_device1, false, false);
firewall_notifier->device_status_changed(&test_device1, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
check_rules(assert_rule_not_exists, 0, device_rules,
......@@ -4466,12 +4496,12 @@ static void firewall_test_device_status_fail0()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* NULL device on */
firewall_notifier->device_status_changed(NULL, true, false);
firewall_notifier->device_status_changed(NULL, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* NULL device off */
firewall_notifier->device_status_changed(NULL, false, false);
firewall_notifier->device_status_changed(NULL, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
......@@ -4496,12 +4526,12 @@ static void firewall_test_device_status_fail1()
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* Device with no inteface on */
firewall_notifier->device_status_changed(&test_device3, true, false);
firewall_notifier->device_status_changed(&test_device3, true);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
/* Device with no inteface off */
firewall_notifier->device_status_changed(&test_device3, false, false);
firewall_notifier->device_status_changed(&test_device3, false);
g_assert_cmpint(g_slist_length(rules_ipv4), ==, RULES_GEN4);
g_assert_cmpint(g_slist_length(rules_ipv6), ==, RULES_GEN6);
......
......@@ -503,6 +503,7 @@ struct connman_device {
const char *ident;
const char *ifname;
int refcount;
bool managed;
};
static struct connman_device test_device1 = {
......@@ -511,6 +512,7 @@ static struct connman_device test_device1 = {
.ident = "gadget123",
.ifname = "rndis0",
.refcount = 0,
.managed = true,
};
static struct connman_device test_device2 = {
......@@ -519,6 +521,7 @@ static struct connman_device test_device2 = {
.ident = "unknown456",
.ifname = "rndis0",
.refcount = 0,
.managed = true,
};
static struct connman_device test_device3 = {
......@@ -527,6 +530,7 @@ static struct connman_device test_device3 = {
.ident = "gadget789",
.ifname = "rndis0",
.refcount = 0,
.managed = true,
};
static struct connman_device test_device4 = {
......@@ -535,6 +539,7 @@ static struct connman_device test_device4 = {
.ident = "ethernet321",
.ifname = "rndis1",
.refcount = 0,
.managed = true,
};
......@@ -608,14 +613,29 @@ enum device_notify_status { NOTIFY_UNSET = 0, NOTIFY_TRUE, NOTIFY_FALSE };
static struct connman_device *notify_device = NULL;
static enum device_notify_status notify_status = NOTIFY_UNSET;
void connman_device_status_notify(struct connman_device *device, bool status,
bool managed)
bool connman_device_get_managed(struct connman_device *device)
{
g_assert(device);
return device->managed;
}
void connman_device_set_managed(struct connman_device *device, bool managed)
{
DBG("");
g_assert(device);
g_assert_false(managed);
device->managed = managed;
}
void connman_device_status_notify(struct connman_device *device, bool status)
{
DBG("%p %s", device, status ? "on" : "off");
notify_device = device;
notify_status = status ? NOTIFY_TRUE : NOTIFY_FALSE;
g_assert(managed == false);
}
// rtnl dummies
......@@ -804,6 +824,9 @@ void reset_test(void)
test_interface_index = -1;
set_usb_moded_ignore(IGNORE_UNSET);
rtnl_on = true;
test_device1.managed = test_device2.managed = test_device3.managed =
test_device4.managed = true;
}
/* Device enabling, all status changes and react to D-Bus reply */
......@@ -951,12 +974,14 @@ static void developer_mode_plugin_test_rtnl3()
g_assert(notify_status == NOTIFY_UNSET);
g_assert_cmpint(test_device1.refcount, ==, 0);
/* If the device is valid, remove notification is sent */
/*
* If the device is valid but not set up by the plugin, remove
* notification is not sent
*/
set_test_interface(&test_device1);
send_dbus_signal("developer_mode");
rtnl_device_off(test_device1.index, 0);
g_assert(notify_status == NOTIFY_FALSE);
g_assert(notify_device == &test_device1);
g_assert(notify_status == NOTIFY_UNSET);
g_assert_cmpint(test_device1.refcount, ==, 0);
__connman_builtin_sailfish_developer_mode.exit();
......@@ -1250,6 +1275,49 @@ static void developer_mode_plugin_test_rtnl8()
__connman_builtin_sailfish_developer_mode.exit();
}
/*
* Test by first enabling device normally and then change managed to true
* before setting the device off
*/
static void developer_mode_plugin_test_rtnl9()
{
reset_test();
set_test_interface(&test_device1);
g_assert(__connman_builtin_sailfish_developer_mode.init() == 0);
rtnl_device_on(test_device1.index, IFF_UP|IFF_RUNNING|IFF_LOWER_UP);
/* Query has been made, no notify is done, reference is kept */
g_assert(sent_message);
g_assert(notify_status == NOTIFY_UNSET);
g_assert_cmpint(test_device1.refcount, ==, 1);
/* Notify with device1 interface */
call_dbus_pending_notify();
g_assert(notify_status == NOTIFY_TRUE);
g_assert(notify_device == &test_device1);
g_assert_cmpint(test_device1.refcount, ==, 1);
/* No new query has been made */
g_assert_null(sent_message);
g_assert_null(pending_call);
reset_dbus_pending_notify();
reset_notify();