core/cli: allow activations with only one of [ device, connection ] (bgo #707427) (rh #961543)

If a connection is given but no device, the correct device will be
automatically determined.

If a device is given but not a connection, a connection will be
automatically chose from among that device's available connections.

Adds the cli command "nmcli dev connect <ifname>".
This commit is contained in:
Dan Williams 2013-10-31 15:47:15 -05:00
commit 732012cc8c
12 changed files with 387 additions and 67 deletions

View file

@ -502,6 +502,13 @@ _nmcli_complete_COMMAND_CONNECTION()
fi
words=("${words[@]:2}")
;;
ifname)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_list_nl "$(_nmcli_NM_devices)"
return 0
fi
words=("${words[@]:2}")
;;
*)
COMMAND_CONNECTION_TYPE=
COMMAND_CONNECTION_ID="${words[0]}"
@ -601,12 +608,18 @@ _nmcli()
;;
u|up)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_list_nl "$(printf "id\nuuid\npath\n%s" "$(_nmcli_con_id)")"
_nmcli_list_nl "$(printf "ifname\nid\nuuid\npath\n%s" "$(_nmcli_con_id)")"
elif [[ ${#words[@]} -gt 3 ]]; then
local COMMAND_CONNECTION_TYPE=''
words=("${words[@]:2}")
OPTIONS=(id uuid path)
OPTIONS=(ifname id uuid path)
_nmcli_complete_COMMAND_CONNECTION && return 0
OPTIONS=(ifname ap nsp)
if [[ "$COMMAND_CONNECTION_TYPE" = "ifname" ]]; then
OPTIONS=(ap nsp)
else
OPTIONS=(ifname ap nsp)
fi
_nmcli_complete_COMMAND_ARGS
fi
;;
@ -841,12 +854,13 @@ _nmcli()
;;
d|de|dev|devi|devic|device)
if [[ ${#words[@]} -eq 2 ]]; then
_nmcli_list "status show disconnect wifi wimax help"
_nmcli_list "status show connect disconnect wifi wimax help"
elif [[ ${#words[@]} -gt 2 ]]; then
case "$command" in
s|st|sta|stat|statu|status)
;;
sh|sho|show| \
c|co|con|conn|conne|connec|connect| \
d|di|dis|disc|disco|discon|disconn|disconne|disconnec|disconnect)
if [[ ${#words[@]} -eq 3 ]]; then
_nmcli_list_nl "$(_nmcli_NM_devices)"

View file

@ -218,9 +218,9 @@ usage (void)
" show configured [[ id | uuid | path ] <ID>]\n\n"
" show active [[ id | uuid | path | apath ] <ID>]\n\n"
#if WITH_WIMAX
" up [ id | uuid | path ] <ID> [ifname <ifname>] [ap <BSSID>] [nsp <name>]\n\n"
" up [[ id | uuid | path ] <ID>] [ifname <ifname>] [ap <BSSID>] [nsp <name>]\n\n"
#else
" up [ id | uuid | path ] <ID> [ifname <ifname>] [ap <BSSID>]\n\n"
" up [[ id | uuid | path ] <ID>] [ifname <ifname>] [ap <BSSID>]\n\n"
#endif
" down [ id | uuid | path | apath ] <ID>\n\n"
" add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS\n\n"
@ -1517,18 +1517,31 @@ nmc_activate_connection (NmCli *nmc,
GError *local = NULL;
g_return_val_if_fail (nmc != NULL, FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection) || ifname, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (nm_connection_get_virtual_iface_name (connection))
is_virtual = TRUE;
if (connection) {
if (nm_connection_get_virtual_iface_name (connection))
is_virtual = TRUE;
device_found = find_device_for_connection (nmc, connection, ifname, ap, nsp, &device, &spec_object, &local);
/* Virtual connection may not have their interfaces created yet */
if (!device_found && !is_virtual) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_CON_ACTIVATION,
"%s", local && local->message ? local->message : _("unknown error"));
g_clear_error (&local);
device_found = find_device_for_connection (nmc, connection, ifname, ap, nsp, &device, &spec_object, &local);
/* Virtual connection may not have their interfaces created yet */
if (!device_found && !is_virtual) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_CON_ACTIVATION,
"%s", local && local->message ? local->message : _("unknown error"));
g_clear_error (&local);
return FALSE;
}
} else if (ifname) {
device = nm_client_get_device_by_iface (nmc->client, ifname);
if (!device) {
g_set_error (error, NMCLI_ERROR, NMC_RESULT_ERROR_CON_ACTIVATION,
_("unknown device '%s'."), ifname);
return FALSE;
}
} else {
g_set_error_literal (error, NMCLI_ERROR, NMC_RESULT_ERROR_CON_ACTIVATION,
_("no connection and no device given."));
return FALSE;
}
@ -1554,7 +1567,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
const char *nsp = NULL;
GError *error = NULL;
const char *selector = NULL;
const char *name;
const char *name = NULL;
char *line = NULL;
/*
@ -1570,12 +1583,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
name = line ? line : "";
// TODO: enhancement: when just Enter is pressed (line is NULL), list
// available connections so that the user can select one
} else {
g_string_printf (nmc->return_text, _("Error: No connection specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
} else {
} else if (strcmp (*argv, "ifname") != 0) {
if ( strcmp (*argv, "id") == 0
|| strcmp (*argv, "uuid") == 0
|| strcmp (*argv, "path") == 0) {
@ -1589,16 +1598,11 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
name = *argv;
}
name = *argv;
next_arg (&argc, &argv);
}
connection = find_connection (nmc->system_connections, selector, name);
if (!connection) {
g_string_printf (nmc->return_text, _("Error: Unknown connection: %s."), name);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
goto error;
}
next_arg (&argc, &argv);
if (name)
connection = find_connection (nmc->system_connections, selector, name);
while (argc > 0) {
if (strcmp (*argv, "ifname") == 0) {

View file

@ -262,12 +262,13 @@ usage (void)
fprintf (stderr,
_("Usage: nmcli device { COMMAND | help }\n\n"
#if WITH_WIMAX
" COMMAND := { status | show | disconnect | wifi | wimax }\n\n"
" COMMAND := { status | show | connect | disconnect | wifi | wimax }\n\n"
#else
" COMMAND := { status | show | disconnect | wifi }\n\n"
" COMMAND := { status | show | connect | disconnect | wifi }\n\n"
#endif
" status\n\n"
" show [<ifname>]\n\n"
" connect <ifname>\n\n"
" disconnect <ifname>\n\n"
" wifi [list [ifname <ifname>] [bssid <BSSID>]]\n\n"
" wifi connect <(B)SSID> [password <password>] [wep-key-type key|phrase] [ifname <ifname>] [bssid <BSSID>] [name <name>]\n\n"
@ -1142,20 +1143,6 @@ error:
return nmc->return_value;
}
static void
device_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
{
NmCli *nmc = (NmCli *) user_data;
NMDeviceState state;
state = nm_device_get_state (device);
if (state == NM_DEVICE_STATE_DISCONNECTED) {
g_string_printf (nmc->return_text, _("Success: Device '%s' successfully disconnected."), nm_device_get_iface (device));
quit ();
}
}
static gboolean
timeout_cb (gpointer user_data)
{
@ -1179,6 +1166,160 @@ progress_cb (gpointer user_data)
return TRUE;
}
static void
connected_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
{
NmCli *nmc = (NmCli *) user_data;
NMDeviceState state;
state = nm_device_get_state (device);
if (state == NM_DEVICE_STATE_ACTIVATED) {
g_string_printf (nmc->return_text, _("Success: Device '%s' successfully activated."), nm_device_get_iface (device));
quit ();
}
}
static void
connect_device_cb (NMClient *client, NMActiveConnection *active, GError *error, gpointer user_data)
{
NmCli *nmc = (NmCli *) user_data;
const GPtrArray *devices;
NMDevice *device;
NMDeviceState state;
if (error) {
g_string_printf (nmc->return_text, _("Error: Device activation failed: %s"),
error->message ? error->message : _("(unknown)"));
nmc->return_value = NMC_RESULT_ERROR_CON_ACTIVATION;
quit ();
} else {
g_assert (active);
devices = nm_active_connection_get_devices (active);
g_assert (devices && devices->len);
device = g_ptr_array_index (devices, 0);
g_assert (device);
state = nm_device_get_state (device);
if (nmc->nowait_flag || state == NM_DEVICE_STATE_ACTIVATED) {
/* Don't want to wait or device already activated */
if (state == NM_DEVICE_STATE_ACTIVATED && nmc->print_output == NMC_PRINT_PRETTY) {
nmc_terminal_erase_line ();
printf (_("Device '%s' has been connected.\n"), nm_device_get_iface (device));
}
quit ();
} else {
g_signal_connect (device, "notify::state", G_CALLBACK (connected_state_cb), nmc);
/* Start timer not to loop forever if "notify::state" signal is not issued */
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
}
}
}
static NMCResultCode
do_device_connect (NmCli *nmc, int argc, char **argv)
{
NMDevice **devices;
NMDevice *device = NULL;
const char *ifname = NULL;
char *ifname_ask = NULL;
int i;
/* Set default timeout for connect operation. */
if (nmc->timeout == -1)
nmc->timeout = 90;
if (argc == 0) {
if (nmc->ask) {
ifname = ifname_ask = nmc_get_user_input (_("Interface: "));
// TODO: list available devices when just Enter is pressed ?
}
if (!ifname_ask) {
g_string_printf (nmc->return_text, _("Error: No interface specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
} else {
ifname = *argv;
}
if (!ifname) {
g_string_printf (nmc->return_text, _("Error: No interface specified."));
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
if (next_arg (&argc, &argv) == 0) {
g_string_printf (nmc->return_text, _("Error: extra argument not allowed: '%s'."), *argv);
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto error;
}
nmc->get_client (nmc);
if (!nm_client_get_manager_running (nmc->client)) {
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
goto error;
}
if (!nmc_versions_match (nmc))
goto error;
devices = get_devices_sorted (nmc->client);
for (i = 0; devices[i]; i++) {
NMDevice *candidate = devices[i];
const char *dev_iface = nm_device_get_iface (candidate);
if (!g_strcmp0 (dev_iface, ifname))
device = candidate;
}
g_free (devices);
if (!device) {
g_string_printf (nmc->return_text, _("Error: Device '%s' not found."), ifname);
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
goto error;
}
/*
* Use nowait_flag instead of should_wait, because exiting has to be postponed
* till connect_device_cb() is called, giving NM time to check our permissions.
*/
nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait = TRUE;
nm_client_activate_connection (nmc->client,
NULL, /* let NM find a connection automatically */
device,
NULL,
connect_device_cb,
nmc);
/* Start progress indication */
if (nmc->print_output == NMC_PRINT_PRETTY)
progress_id = g_timeout_add (120, progress_cb, device);
error:
g_free (ifname_ask);
return nmc->return_value;
}
static void
disconnect_state_cb (NMDevice *device, GParamSpec *pspec, gpointer user_data)
{
NmCli *nmc = (NmCli *) user_data;
NMDeviceState state;
state = nm_device_get_state (device);
if (state == NM_DEVICE_STATE_DISCONNECTED) {
g_string_printf (nmc->return_text, _("Success: Device '%s' successfully disconnected."), nm_device_get_iface (device));
quit ();
}
}
static void
disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
{
@ -1204,7 +1345,7 @@ disconnect_device_cb (NMDevice *device, GError *error, gpointer user_data)
}
quit ();
} else {
g_signal_connect (device, "notify::state", G_CALLBACK (device_state_cb), nmc);
g_signal_connect (device, "notify::state", G_CALLBACK (disconnect_state_cb), nmc);
/* Start timer not to loop forever if "notify::state" signal is not issued */
g_timeout_add_seconds (nmc->timeout, timeout_cb, nmc);
}
@ -2296,6 +2437,9 @@ do_devices (NmCli *nmc, int argc, char **argv)
nmc->multiline_output = TRUE; /* multiline mode is default for 'device show' */
nmc->return_value = do_devices_show (nmc, argc-1, argv+1);
}
else if (matches (*argv, "connect") == 0) {
nmc->return_value = do_device_connect (nmc, argc-1, argv+1);
}
else if (matches (*argv, "disconnect") == 0) {
nmc->return_value = do_device_disconnect (nmc, argc-1, argv+1);
}

View file

@ -41,12 +41,17 @@
</tp:docstring>
<arg name="connection" type="o" direction="in">
<tp:docstring>
The connection to activate the devices with.
The connection to activate. If "/" is given, a valid device path must
be given, and NetworkManager picks the best connection to activate for
the given device. VPN connections must always pass a valid connection
path.
</tp:docstring>
</arg>
<arg name="device" type="o" direction="in">
<tp:docstring>
The object path of device to be activated for physical connections. This parameter is ignored for VPN connections, because the specific_object (if provided) specifies the device to use.
The object path of device to be activated for physical connections.
This parameter is ignored for VPN connections, because the
specific_object (if provided) specifies the device to use.
</tp:docstring>
</arg>
<arg name="specific_object" type="o" direction="in">
@ -55,7 +60,7 @@
This parameter is currently ignored for wired and mobile broadband connections,
and the value of "/" should be used (ie, no specific object). For WiFi
connections, pass the object path of a specific AP from the card's scan
list, or "/" to pick and AP automatically. For VPN connections, pass
list, or "/" to pick an AP automatically. For VPN connections, pass
the object path of an ActiveConnection object that should serve as the
"base" connection (to which the VPN connections lifetime will be tied),
or pass "/" and NM will automatically use the current default device.

View file

@ -594,7 +594,7 @@ activate_nm_not_running (gpointer user_data)
/**
* nm_client_activate_connection:
* @client: a #NMClient
* @connection: an #NMConnection
* @connection: (allow-none): an #NMConnection
* @device: (allow-none): the #NMDevice
* @specific_object: (allow-none): the object path of a connection-type-specific
* object this activation should use. This parameter is currently ignored for
@ -613,6 +613,9 @@ activate_nm_not_running (gpointer user_data)
* #NMWimaxNsp for WiMAX connections, to which you wish to connect. If the
* specific object is not given, NetworkManager can, in some cases, automatically
* determine which network to connect to given the settings in @connection.
*
* If @connection is not given for a device-based activation, NetworkManager
* picks the best available connection for the device and activates it.
**/
void
nm_client_activate_connection (NMClient *client,
@ -628,7 +631,8 @@ nm_client_activate_connection (NMClient *client,
g_return_if_fail (NM_IS_CLIENT (client));
if (device)
g_return_if_fail (NM_IS_DEVICE (device));
g_return_if_fail (NM_IS_CONNECTION (connection));
if (connection)
g_return_if_fail (NM_IS_CONNECTION (connection));
info = g_slice_new0 (ActivateInfo);
info->act_fn = callback;
@ -645,7 +649,7 @@ nm_client_activate_connection (NMClient *client,
dbus_g_proxy_begin_call (priv->client_proxy, "ActivateConnection",
activate_cb, info, NULL,
DBUS_TYPE_G_OBJECT_PATH, nm_connection_get_path (connection),
DBUS_TYPE_G_OBJECT_PATH, connection ? nm_connection_get_path (connection) : "/",
DBUS_TYPE_G_OBJECT_PATH, device ? nm_object_get_path (NM_OBJECT (device)) : "/",
DBUS_TYPE_G_OBJECT_PATH, specific_object ? specific_object : "/",
G_TYPE_INVALID);

View file

@ -304,14 +304,20 @@ When no command is given to the \fIconnection\fP object, the default action
is 'nmcli connection show configured'.
.TP
.B up [ id | uuid | path ] <ID> [ifname <ifname>] [ap <BSSID>] [nsp <name>]
.RE
.RS
.B up ifname <ifname> [ap <BSSID>] [nsp <name>]
.RS
.br
Activate a connection. The connection is identified by its name, UUID or D-Bus
path. If <ID> is ambiguous, a keyword \fIid\fP, \fIuuid\fP or \fIpath\fP can be
used. When requiring a particular device to activate the connection on, the
\fIifname\fP option with interface name should be given. In case of a VPN
connection, the \fIifname\fP option specify the device of the base connection.
The \fIap\fP option specify what particular AP should be used in case of
a Wi\(hyFi connection.
used. When requiring a particular device to activate the connection on, the
\fIifname\fP option with interface name should be given. If the <ID> is not
given an \fIifname\fP is required, and NetworkManager will activate the best
available connection for the given \fIifname\fP. In case of a VPN connection,
the \fIifname\fP option specifies the device of the base connection. The
\fIap\fP option specify what particular AP should be used in case of a Wi\(hyFi
connection.
.br
If '--wait' option is not specified, the default timeout will be 90 seconds.
.br
@ -326,6 +332,7 @@ Available options are:
.IP \fInsp\fP 13
\(en NSP (Network Service Provider) which the command should connect to (for WiMAX connections)
.RE
.RE
.TP
.B down [ id | uuid | path | apath ] <ID>
.br
@ -608,7 +615,7 @@ then \fINetworkManager\fP will reload connection files any time they change
.B device - show and manage network interfaces
.br
.TP
.SS \fICOMMAND\fP := { status | show | disconnect | wifi | wimax }
.SS \fICOMMAND\fP := { status | show | connect | disconnect | wifi | wimax }
.sp
.RS
.TP
@ -624,6 +631,13 @@ Show detailed information about devices. Without an argument, all devices are
examined. To get information for a specific device, the interface name has
to be provided.
.TP
.B connect <ifname>
.br
Connect the device. NetworkManager will try to find a suitable connection that
will be activated. It will also consider connections that are not set to auto connect.
.br
If '--wait' option is not specified, the default timeout will be 90 seconds.
.TP
.B disconnect <ifname>
.br
Disconnect a device and prevent the device from automatically activating further

View file

@ -221,7 +221,9 @@ check_connection_compatible (NMDevice *device,
}
static gboolean
check_connection_available (NMDevice *device, NMConnection *connection)
check_connection_available (NMDevice *device,
NMConnection *connection,
const char *specific_object)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
guint32 bt_type;

View file

@ -1021,13 +1021,22 @@ check_connection_compatible (NMDevice *device,
static gboolean
check_connection_available (NMDevice *device, NMConnection *connection)
check_connection_available (NMDevice *device,
NMConnection *connection,
const char *specific_object)
{
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device);
NMSettingWireless *s_wifi;
const char *mode;
GSList *ap_iter = NULL;
if (specific_object) {
NMAccessPoint *ap;
ap = get_ap_by_path (NM_DEVICE_WIFI (device), specific_object);
return ap ? nm_ap_check_compatible (ap, connection) : FALSE;
}
s_wifi = nm_connection_get_setting_wireless (connection);
/* Ad-Hoc and AP connections are always available because they may be

View file

@ -320,7 +320,9 @@ static gboolean nm_device_set_ip6_config (NMDevice *dev,
static gboolean nm_device_activate_ip6_config_commit (gpointer user_data);
static gboolean check_connection_available (NMDevice *device, NMConnection *connection);
static gboolean check_connection_available (NMDevice *device,
NMConnection *connection,
const char *specific_object);
static gboolean spec_match_list (NMDevice *device, const GSList *specs);
@ -6613,7 +6615,7 @@ _try_add_available_connection (NMDevice *self, NMConnection *connection)
if (nm_device_check_connection_compatible (self, connection, NULL)) {
/* Let subclasses implement additional checks on the connection */
if ( NM_DEVICE_GET_CLASS (self)->check_connection_available
&& NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection)) {
&& NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, NULL)) {
g_hash_table_insert (NM_DEVICE_GET_PRIVATE (self)->available_connections,
g_object_ref (connection),
@ -6631,7 +6633,9 @@ _del_available_connection (NMDevice *device, NMConnection *connection)
}
static gboolean
check_connection_available (NMDevice *device, NMConnection *connection)
check_connection_available (NMDevice *device,
NMConnection *connection,
const char *specific_object)
{
/* Default is to assume the connection is available unless a subclass
* overrides this with more specific checks.
@ -6658,6 +6662,42 @@ nm_device_recheck_available_connections (NMDevice *device)
_signal_available_connections_changed (device);
}
/**
* nm_device_get_available_connections:
* @device: the #NMDevice
* @specific_object: a specific object path if any
*
* Returns a list of connections available to activate on the device, taking
* into account any device-specific details given by @specific_object (like
* WiFi access point path).
*
* Returns: caller-owned #GPtrArray of #NMConnections
*/
GPtrArray *
nm_device_get_available_connections (NMDevice *device, const char *specific_object)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
GHashTableIter iter;
guint num_available;
NMConnection *connection = NULL;
GPtrArray *array = NULL;
num_available = g_hash_table_size (priv->available_connections);
if (num_available > 0) {
array = g_ptr_array_sized_new (num_available);
g_hash_table_iter_init (&iter, priv->available_connections);
while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) {
/* If a specific object is given, only include connections that are
* compatible with it.
*/
if ( !specific_object
|| NM_DEVICE_GET_CLASS (device)->check_connection_available (device, connection, specific_object))
g_ptr_array_add (array, connection);
}
}
return array;
}
static void
cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data)
{

View file

@ -140,11 +140,13 @@ typedef struct {
GError **error);
/* Checks whether the connection is likely available to be activated,
* including any live network information like scan lists. Returns
* TRUE if the connection is available; FALSE if not.
* including any live network information like scan lists. The connection
* is checked against the object defined by @specific_object, if given.
* Returns TRUE if the connection is available; FALSE if not.
*/
gboolean (* check_connection_available) (NMDevice *self,
NMConnection *connection);
NMConnection *connection,
const char *specific_object);
gboolean (* complete_connection) (NMDevice *self,
NMConnection *connection,
@ -337,6 +339,9 @@ void nm_device_add_pending_action (NMDevice *device, const char *action);
void nm_device_remove_pending_action (NMDevice *device, const char *action);
gboolean nm_device_has_pending_action (NMDevice *device);
GPtrArray *nm_device_get_available_connections (NMDevice *device,
const char *specific_object);
G_END_DECLS
/* For testing only */

View file

@ -261,6 +261,22 @@ get_nsp_by_name (NMDeviceWimax *self, const char *name)
return NULL;
}
static NMWimaxNsp *
get_nsp_by_path (NMDeviceWimax *self, const char *path)
{
NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self);
GSList *iter;
for (iter = priv->nsp_list; iter; iter = iter->next) {
NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data);
if (!g_strcmp0 (nm_wimax_nsp_get_dbus_path (nsp), path))
return nsp;
}
return NULL;
}
static gboolean
update_availability (NMDeviceWimax *self, gboolean old_available)
{
@ -375,10 +391,18 @@ check_connection_compatible (NMDevice *device,
}
static gboolean
check_connection_available (NMDevice *device, NMConnection *connection)
check_connection_available (NMDevice *device,
NMConnection *connection,
const char *specific_object)
{
NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device);
const GSList *ns_iter = NULL;
NMWimaxNsp *nsp;
if (specific_object) {
nsp = get_nsp_by_path (NM_DEVICE_WIMAX (device), specific_object);
return nsp ? nm_wimax_nsp_check_compatible (nsp, connection) : FALSE;
}
/* Ensure the connection applies to an NSP in the scan list */
for (ns_iter = priv->nsp_list; ns_iter; ns_iter = ns_iter->next) {

View file

@ -3110,6 +3110,61 @@ impl_manager_activate_connection (NMManager *self,
gboolean is_vpn = FALSE;
GError *error = NULL;
/* Normalize object paths */
if (g_strcmp0 (connection_path, "/") == 0)
connection_path = NULL;
if (g_strcmp0 (specific_object_path, "/") == 0)
specific_object_path = NULL;
if (g_strcmp0 (device_path, "/") == 0)
device_path = NULL;
/* If the connection path is given and valid, that connection is activated.
* Otherwise the "best" connection for the device is chosen and activated,
* regardless of whether that connection is autoconnect-enabled or not
* (since this is an explicit request, not an auto-activation request).
*/
if (!connection_path) {
GPtrArray *available;
guint64 best_timestamp = 0;
guint i;
/* If no connection is given, find a suitable connection for the given device path */
if (!device_path) {
error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Only devices may be activated without a specifying a connection");
goto error;
}
device = nm_manager_get_device_by_path (self, device_path);
if (!device) {
error = g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Cannot activate unknown device %s", device_path);
goto error;
}
available = nm_device_get_available_connections (device, specific_object_path);
for (i = 0; available && i < available->len; i++) {
NMSettingsConnection *candidate = g_ptr_array_index (available, i);
guint64 candidate_timestamp = 0;
nm_settings_connection_get_timestamp (candidate, &candidate_timestamp);
if (!connection_path || (candidate_timestamp > best_timestamp)) {
connection_path = nm_connection_get_path (NM_CONNECTION (candidate));
best_timestamp = candidate_timestamp;
}
}
if (available)
g_ptr_array_free (available, TRUE);
if (!connection_path) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
"The device has no connections available.");
goto error;
}
}
g_assert (connection_path);
connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path);
if (!connection) {
error = g_error_new_literal (NM_MANAGER_ERROR,