diff options
| author | Michael Biebl <biebl@debian.org> | 2015-08-28 01:13:48 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2015-08-28 01:13:48 +0200 |
| commit | 81836c2d44802b4cca833d7775dd627e0797a7e2 (patch) | |
| tree | 91154e6cefc0465306603f51ec0010d9963bbea4 /src/devices | |
| parent | 50a58f0fabd8a34c1b6108a107e08abe3c1ccd24 (diff) | |
Imported Upstream version 1.0.6 upstream/1.0.6
Diffstat (limited to 'src/devices')
| -rw-r--r-- | src/devices/nm-device-ethernet.c | 60 | ||||
| -rw-r--r-- | src/devices/nm-device-infiniband.c | 2 | ||||
| -rw-r--r-- | src/devices/nm-device-logging.h | 10 | ||||
| -rw-r--r-- | src/devices/nm-device-macvlan.c | 5 | ||||
| -rw-r--r-- | src/devices/nm-device-vlan.c | 41 | ||||
| -rw-r--r-- | src/devices/nm-device.c | 438 | ||||
| -rw-r--r-- | src/devices/nm-device.h | 3 | ||||
| -rw-r--r-- | src/devices/team/nm-device-team.c | 21 | ||||
| -rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 39 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-ap.c | 25 | ||||
| -rw-r--r-- | src/devices/wifi/nm-wifi-ap.h | 1 |
11 files changed, 486 insertions, 159 deletions
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index af2cb8f2..beb86e11 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -53,6 +53,7 @@ #include "nm-device-factory.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" +#include "gsystem-local-alloc.h" #include "nm-device-ethernet-glue.h" @@ -66,6 +67,7 @@ G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE) #define WIRED_SECRETS_TRIES "wired-secrets-tries" #define PPPOE_RECONNECT_DELAY 7 +#define PPPOE_ENCAP_OVERHEAD 8 /* 2 bytes for PPP, 6 for PPPoE */ static NMSetting *device_get_setting (NMDevice *device, GType setting_type); @@ -1174,6 +1176,40 @@ dcb_carrier_changed (NMDevice *device, GParamSpec *pspec, gpointer unused) /****************************************************************/ +static gboolean +wake_on_lan_enable (NMDevice *device) +{ + NMSettingWiredWakeOnLan wol; + NMSettingWired *s_wired; + const char *password = NULL; + gs_free char *value = NULL; + + s_wired = (NMSettingWired *) device_get_setting (device, NM_TYPE_SETTING_WIRED); + if (s_wired) { + wol = nm_setting_wired_get_wake_on_lan (s_wired); + password = nm_setting_wired_get_wake_on_lan_password (s_wired); + if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + goto found; + } + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ethernet.wake-on-lan", + device); + if (value) { + wol = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_WIRED_WAKE_ON_LAN_NONE, + NM_SETTING_WIRED_WAKE_ON_LAN_ALL, + NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT); + if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) + goto found; + } + wol = NM_SETTING_WIRED_WAKE_ON_LAN_NONE; +found: + return nmp_utils_ethtool_set_wake_on_lan (nm_device_get_iface (device), wol, password); +} + +/****************************************************************/ + static NMActStageReturn act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) { @@ -1206,6 +1242,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } } + wake_on_lan_enable (device); + /* DCB and FCoE setup */ s_dcb = (NMSettingDcb *) device_get_setting (device, NM_TYPE_SETTING_DCB); if (s_dcb) { @@ -1231,6 +1269,28 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) ret = NM_ACT_STAGE_RETURN_POSTPONE; } + /* PPPoE setup */ + if (nm_connection_is_type (nm_device_get_connection (device), + NM_SETTING_PPPOE_SETTING_NAME)) { + NMSettingPpp *s_ppp; + + s_ppp = (NMSettingPpp *) device_get_setting (device, NM_TYPE_SETTING_PPP); + if (s_ppp) { + guint32 mtu = 0, mru = 0, mxu; + + mtu = nm_setting_ppp_get_mtu (s_ppp); + mru = nm_setting_ppp_get_mru (s_ppp); + mxu = mru > mtu ? mru : mtu; + if (mxu) { + _LOGD (LOGD_PPP, "set MTU to %u (PPP interface MRU %u, MTU %u)", + mxu + PPPOE_ENCAP_OVERHEAD, mru, mtu); + nm_platform_link_set_mtu (NM_PLATFORM_GET, + nm_device_get_ifindex (device), + mxu + PPPOE_ENCAP_OVERHEAD); + } + } + } + return ret; } diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 2e2483c0..2d519f61 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -313,7 +313,7 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, NM_DEVICE_PLATFORM_DEVICE, plink, NM_DEVICE_TYPE_DESC, "InfiniBand", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NM_DEVICE_INFINIBAND_IS_PARTITION, (plink->parent > 0), + NM_DEVICE_INFINIBAND_IS_PARTITION, (plink->parent > 0 || plink->parent == NM_PLATFORM_LINK_OTHER_NETNS), NULL); } diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h index acca32e5..f3b76ee8 100644 --- a/src/devices/nm-device-logging.h +++ b/src/devices/nm-device-logging.h @@ -31,16 +31,12 @@ _nm_device_log_self_to_device (t *self) \ return (NMDevice *) self; \ } -#define _LOG(level, domain, ...) \ +#undef _NMLOG_ENABLED +#define _NMLOG_ENABLED(level, domain) ( nm_logging_enabled ((level), (domain)) ) +#define _NMLOG(level, domain, ...) \ nm_log_obj ((level), (domain), (self), \ "(%s): " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ (self) ? str_if_set (nm_device_get_iface (_nm_device_log_self_to_device (self)), "(null)") : "(none)" \ _NM_UTILS_MACRO_REST(__VA_ARGS__)) -#define _LOGT(domain, ...) _LOG (LOGL_TRACE, domain, __VA_ARGS__) -#define _LOGD(domain, ...) _LOG (LOGL_DEBUG, domain, __VA_ARGS__) -#define _LOGI(domain, ...) _LOG (LOGL_INFO, domain, __VA_ARGS__) -#define _LOGW(domain, ...) _LOG (LOGL_WARN, domain, __VA_ARGS__) -#define _LOGE(domain, ...) _LOG (LOGL_ERR, domain, __VA_ARGS__) - #endif /* __NETWORKMANAGER_DEVICE_LOGGING_H__ */ diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 0bfe3fe9..2a815cfd 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -114,7 +114,10 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PARENT: - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + if (priv->props.parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + else + parent = NULL; g_value_set_boxed (value, parent ? nm_device_get_path (parent) : "/"); break; case PROP_MODE: diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 158e7de5..e523e6bb 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -181,7 +181,8 @@ component_added (NMDevice *device, GObject *component) return FALSE; } - if (nm_device_get_ifindex (added_device) != parent_ifindex) + if ( parent_ifindex <= 0 + || nm_device_get_ifindex (added_device) != parent_ifindex) return FALSE; nm_device_vlan_set_parent (self, added_device, FALSE); @@ -356,23 +357,28 @@ update_connection (NMDevice *device, NMConnection *connection) if (vlan_id != nm_setting_vlan_get_id (s_vlan)) g_object_set (s_vlan, NM_SETTING_VLAN_ID, priv->vlan_id, NULL); - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - g_assert (parent); + if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + else + parent = NULL; nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE); /* Update parent in the connection; default to parent's interface name */ - new_parent = nm_device_get_iface (parent); - setting_parent = nm_setting_vlan_get_parent (s_vlan); - if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnection *parent_connection; - - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) - new_parent = NULL; - } - if (new_parent) - g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL); + if (parent) { + new_parent = nm_device_get_iface (parent); + setting_parent = nm_setting_vlan_get_parent (s_vlan); + if (setting_parent && nm_utils_is_uuid (setting_parent)) { + NMConnection *parent_connection; + + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); + if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + new_parent = NULL; + } + if (new_parent) + g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL); + } else + g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL); } static NMActStageReturn @@ -628,7 +634,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, "VLAN parent ifindex unknown"); return NULL; } - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + if (parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + else + parent = NULL; device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c5d4c203..58895821 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -75,6 +75,10 @@ _LOG_DECLARE_SELF (NMDevice); static void impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context); static void impl_device_delete (NMDevice *self, DBusGMethodInvocation *context); static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data); +static gboolean ip_config_valid (NMDeviceState state); +static void nm_device_update_metered (NMDevice *self); +static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, NMDeviceStateReason *reason); +static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason); #include "nm-device-glue.h" @@ -128,6 +132,7 @@ enum { PROP_MASTER, PROP_HW_ADDRESS, PROP_HAS_PENDING_ACTION, + PROP_METERED, LAST_PROP }; @@ -269,18 +274,20 @@ typedef struct { struct { gboolean v4_has; gboolean v4_is_assumed; - gboolean v4_configure_first_time; NMPlatformIP4Route v4; gboolean v6_has; gboolean v6_is_assumed; - gboolean v6_configure_first_time; NMPlatformIP6Route v6; } default_route; + gboolean v4_commit_first_time; + gboolean v6_commit_first_time; + /* DHCPv4 tracking */ NMDhcpClient * dhcp4_client; gulong dhcp4_state_sigid; NMDhcp4Config * dhcp4_config; + guint dhcp4_restart_id; NMIP4Config * vpn4_config; /* routes added by a VPN which uses this device */ guint arp_round2_id; @@ -325,6 +332,9 @@ typedef struct { NMDhcp6Config * dhcp6_config; /* IP6 config from DHCP */ NMIP6Config * dhcp6_ip6_config; + /* Event ID of the current IP6 config from DHCP */ + char * dhcp6_event_id; + guint dhcp6_restart_id; /* allow autoconnect feature */ gboolean autoconnect; @@ -338,6 +348,8 @@ typedef struct { gboolean is_master; GSList * slaves; /* list of SlaveInfo */ + NMMetered metered; + NMConnectionProvider *con_provider; } NMDevicePrivate; @@ -687,6 +699,21 @@ nm_device_get_device_type (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->type; } +/** + * nm_device_get_metered: + * @setting: the #NMDevice + * + * Returns: the #NMDevice:metered property of the device. + * + * Since: 1.0.6 + **/ +NMMetered +nm_device_get_metered (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NM_METERED_UNKNOWN); + + return NM_DEVICE_GET_PRIVATE (self)->metered; +} /** * nm_device_get_priority(): @@ -735,14 +762,14 @@ nm_device_get_priority (NMDevice *self) return 400; case NM_DEVICE_TYPE_BRIDGE: return 425; - case NM_DEVICE_TYPE_MODEM: - return 450; - case NM_DEVICE_TYPE_BT: - return 550; case NM_DEVICE_TYPE_WIFI: return 600; case NM_DEVICE_TYPE_OLPC_MESH: return 650; + case NM_DEVICE_TYPE_MODEM: + return 700; + case NM_DEVICE_TYPE_BT: + return 750; case NM_DEVICE_TYPE_GENERIC: return 950; case NM_DEVICE_TYPE_UNKNOWN: @@ -3181,6 +3208,8 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + nm_clear_g_source (&priv->dhcp4_restart_id); + if (priv->dhcp4_client) { /* Stop any ongoing DHCP transaction on this device */ if (priv->dhcp4_state_sigid) { @@ -3218,6 +3247,8 @@ ip4_config_merge_and_apply (NMDevice *self, guint32 gateway; gboolean connection_has_default_route, connection_is_never_default; gboolean routes_full_sync; + gboolean ignore_auto_routes = FALSE; + gboolean ignore_auto_dns = FALSE; /* Merge all the configs into the composite config */ if (config) { @@ -3225,44 +3256,45 @@ ip4_config_merge_and_apply (NMDevice *self, priv->dev_ip4_config = g_object_ref (config); } + /* Apply ignore-auto-routes and ignore-auto-dns settings */ + connection = nm_device_get_connection (self); + if (connection) { + NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (connection); + + if (s_ip4) { + ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4); + ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4); + } + } + composite = nm_ip4_config_new (); if (commit) ensure_con_ip4_config (self); - if (priv->dev_ip4_config) - nm_ip4_config_merge (composite, priv->dev_ip4_config); + if (priv->dev_ip4_config) { + nm_ip4_config_merge (composite, priv->dev_ip4_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); + } if (priv->vpn4_config) - nm_ip4_config_merge (composite, priv->vpn4_config); + nm_ip4_config_merge (composite, priv->vpn4_config, NM_IP_CONFIG_MERGE_DEFAULT); if (priv->ext_ip4_config) - nm_ip4_config_merge (composite, priv->ext_ip4_config); + nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); /* Merge WWAN config *last* to ensure modem-given settings overwrite * any external stuff set by pppd or other scripts. */ - if (priv->wwan_ip4_config) - nm_ip4_config_merge (composite, priv->wwan_ip4_config); - - /* Apply ignore-auto-routes and ignore-auto-dns settings */ - connection = nm_device_get_connection (self); - if (connection) { - NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (connection); - - if (s_ip4) { - if (nm_setting_ip_config_get_ignore_auto_routes (s_ip4)) - nm_ip4_config_reset_routes (composite); - if (nm_setting_ip_config_get_ignore_auto_dns (s_ip4)) { - nm_ip4_config_reset_nameservers (composite); - nm_ip4_config_reset_domains (composite); - nm_ip4_config_reset_searches (composite); - } - } + if (priv->wwan_ip4_config) { + nm_ip4_config_merge (composite, priv->wwan_ip4_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); } /* Merge user overrides into the composite config. For assumed connections, * con_ip4_config is empty. */ if (priv->con_ip4_config) - nm_ip4_config_merge (composite, priv->con_ip4_config); + nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); /* Add the default route. @@ -3282,21 +3314,26 @@ ip4_config_merge_and_apply (NMDevice *self, priv->default_route.v4_has = FALSE; priv->default_route.v4_is_assumed = TRUE; - routes_full_sync = commit - && priv->default_route.v4_configure_first_time - && !nm_device_uses_assumed_connection (self); - if (!commit) { /* during a non-commit event, we always pickup whatever is configured. */ goto END_ADD_DEFAULT_ROUTE; } + if (nm_device_uses_generated_assumed_connection (self)) { + /* a generate-assumed-connection always detects the default route from platform */ + goto END_ADD_DEFAULT_ROUTE; + } + + /* At this point, we treat assumed and non-assumed connections alike. + * For assumed connections we do that because we still manage RA and DHCP + * leases for them, so we must extend/update the default route on commits. + */ + connection_has_default_route = nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, &connection_is_never_default); - if ( !priv->default_route.v4_configure_first_time - && !nm_device_uses_assumed_connection (self) + if ( !priv->v4_commit_first_time && connection_is_never_default) { /* If the connection is explicitly configured as never-default, we enforce the (absense of the) * default-route only once. That allows the user to configure a connection as never-default, @@ -3304,14 +3341,8 @@ ip4_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; } - /* At this point, we treat assumed and non-assumed connections alike. - * For assumed connections we do that because we still manage RA and DHCP - * leases for them, so we must extend/update the default route on commits. - */ - /* we are about to commit (for a non-assumed connection). Enforce whatever we have * configured. */ - priv->default_route.v4_configure_first_time = FALSE; priv->default_route.v4_is_assumed = FALSE; if (!connection_has_default_route) @@ -3323,7 +3354,7 @@ ip4_config_merge_and_apply (NMDevice *self, } gateway = nm_ip4_config_get_gateway (composite); - if ( !gateway + if ( !nm_ip4_config_has_gateway (composite) && nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM) goto END_ADD_DEFAULT_ROUTE; @@ -3365,8 +3396,15 @@ END_ADD_DEFAULT_ROUTE: NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); } + routes_full_sync = commit + && priv->v4_commit_first_time + && !nm_device_uses_assumed_connection (self); + success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync, out_reason); g_object_unref (composite); + + if (commit) + priv->v4_commit_first_time = FALSE; return success; } @@ -3391,12 +3429,44 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) } } +static gboolean +dhcp4_restart_cb (gpointer user_data) +{ + NMDevice *self = user_data; + NMDevicePrivate *priv; + NMDeviceStateReason reason; + NMConnection *connection; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + priv->dhcp4_restart_id = 0; + connection = nm_device_get_connection (self); + + if (dhcp4_start (self, connection, &reason) == NM_ACT_STAGE_RETURN_FAILURE) + priv->dhcp4_restart_id = g_timeout_add_seconds (120, dhcp4_restart_cb, self); + + return FALSE; +} + static void dhcp4_fail (NMDevice *self, gboolean timeout) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); + + /* Don't fail if there are static addresses configured on + * the device, instead retry after some time. + */ + if ( priv->ip4_state == IP_DONE + && priv->con_ip4_config + && nm_ip4_config_get_num_addresses (priv->con_ip4_config) > 0) { + _LOGI (LOGD_DHCP4, "Scheduling DHCPv4 restart because device has IP addresses"); + priv->dhcp4_restart_id = g_timeout_add_seconds (120, dhcp4_restart_cb, self); + return; + } + if (timeout || (priv->ip4_state == IP_CONF)) nm_device_activate_schedule_ip4_config_timeout (self); else if (priv->ip4_state == IP_DONE) @@ -3426,6 +3496,7 @@ dhcp4_state_changed (NMDhcpClient *client, NMDhcpState state, NMIP4Config *ip4_config, GHashTable *options, + const char *event_id, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); @@ -3450,8 +3521,10 @@ dhcp4_state_changed (NMDhcpClient *client, if (priv->ip4_state == IP_CONF) nm_device_activate_schedule_ip4_config_result (self, ip4_config); - else if (priv->ip4_state == IP_DONE) + else if (priv->ip4_state == IP_DONE) { dhcp4_lease_change (self, ip4_config); + nm_device_update_metered (self); + } break; case NM_DHCP_STATE_TIMEOUT: dhcp4_fail (self, TRUE); @@ -3802,6 +3875,9 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE; g_clear_object (&priv->dhcp6_ip6_config); + g_clear_pointer (&priv->dhcp6_event_id, g_free); + + nm_clear_g_source (&priv->dhcp6_restart_id); if (priv->dhcp6_client) { if (priv->dhcp6_state_sigid) { @@ -3837,6 +3913,19 @@ ip6_config_merge_and_apply (NMDevice *self, const struct in6_addr *gateway; gboolean connection_has_default_route, connection_is_never_default; gboolean routes_full_sync; + gboolean ignore_auto_routes = FALSE; + gboolean ignore_auto_dns = FALSE; + + /* Apply ignore-auto-routes and ignore-auto-dns settings */ + connection = nm_device_get_connection (self); + if (connection) { + NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); + + if (s_ip6) { + ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6); + ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6); + } + } /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); @@ -3845,41 +3934,34 @@ ip6_config_merge_and_apply (NMDevice *self, ensure_con_ip6_config (self); /* Merge all the IP configs into the composite config */ - if (priv->ac_ip6_config) - nm_ip6_config_merge (composite, priv->ac_ip6_config); - if (priv->dhcp6_ip6_config) - nm_ip6_config_merge (composite, priv->dhcp6_ip6_config); + if (priv->ac_ip6_config) { + nm_ip6_config_merge (composite, priv->ac_ip6_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); + } + if (priv->dhcp6_ip6_config) { + nm_ip6_config_merge (composite, priv->dhcp6_ip6_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); + } if (priv->vpn6_config) - nm_ip6_config_merge (composite, priv->vpn6_config); + nm_ip6_config_merge (composite, priv->vpn6_config, NM_IP_CONFIG_MERGE_DEFAULT); if (priv->ext_ip6_config) - nm_ip6_config_merge (composite, priv->ext_ip6_config); + nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); /* Merge WWAN config *last* to ensure modem-given settings overwrite * any external stuff set by pppd or other scripts. */ - if (priv->wwan_ip6_config) - nm_ip6_config_merge (composite, priv->wwan_ip6_config); - - /* Apply ignore-auto-routes and ignore-auto-dns settings */ - connection = nm_device_get_connection (self); - if (connection) { - NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); - - if (s_ip6) { - if (nm_setting_ip_config_get_ignore_auto_routes (s_ip6)) - nm_ip6_config_reset_routes (composite); - if (nm_setting_ip_config_get_ignore_auto_dns (s_ip6)) { - nm_ip6_config_reset_nameservers (composite); - nm_ip6_config_reset_domains (composite); - nm_ip6_config_reset_searches (composite); - } - } + if (priv->wwan_ip6_config) { + nm_ip6_config_merge (composite, priv->wwan_ip6_config, + (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) + | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); } /* Merge user overrides into the composite config. For assumed connections, * con_ip6_config is empty. */ if (priv->con_ip6_config) - nm_ip6_config_merge (composite, priv->con_ip6_config); + nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); /* Add the default route. * @@ -3898,21 +3980,26 @@ ip6_config_merge_and_apply (NMDevice *self, priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; - routes_full_sync = commit - && priv->default_route.v6_configure_first_time - && !nm_device_uses_assumed_connection (self); - if (!commit) { /* during a non-commit event, we always pickup whatever is configured. */ goto END_ADD_DEFAULT_ROUTE; } + if (nm_device_uses_generated_assumed_connection (self)) { + /* a generate-assumed-connection always detects the default route from platform */ + goto END_ADD_DEFAULT_ROUTE; + } + + /* At this point, we treat assumed and non-assumed connections alike. + * For assumed connections we do that because we still manage RA and DHCP + * leases for them, so we must extend/update the default route on commits. + */ + connection_has_default_route = nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, &connection_is_never_default); - if ( !priv->default_route.v6_configure_first_time - && !nm_device_uses_assumed_connection (self) + if ( !priv->v6_commit_first_time && connection_is_never_default) { /* If the connection is explicitly configured as never-default, we enforce the (absence of the) * default-route only once. That allows the user to configure a connection as never-default, @@ -3920,14 +4007,8 @@ ip6_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; } - /* At this point, we treat assumed and non-assumed connections alike. - * For assumed connections we do that because we still manage RA and DHCP - * leases for them, so we must extend/update the default route on commits. - */ - /* we are about to commit (for a non-assumed connection). Enforce whatever we have * configured. */ - priv->default_route.v6_configure_first_time = FALSE; priv->default_route.v6_is_assumed = FALSE; if (!connection_has_default_route) @@ -3984,8 +4065,14 @@ END_ADD_DEFAULT_ROUTE: NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, composite); } + routes_full_sync = commit + && priv->v6_commit_first_time + && !nm_device_uses_assumed_connection (self); + success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync, out_reason); g_object_unref (composite); + if (commit) + priv->v6_commit_first_time = FALSE; return success; } @@ -4017,6 +4104,24 @@ dhcp6_lease_change (NMDevice *self) } } +static gboolean +dhcp6_restart_cb (gpointer user_data) +{ + NMDevice *self = user_data; + NMDevicePrivate *priv; + NMDeviceStateReason reason; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + priv->dhcp6_restart_id = 0; + + if (!dhcp6_start (self, FALSE, &reason)) + priv->dhcp6_restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self); + + return FALSE; +} + static void dhcp6_fail (NMDevice *self, gboolean timeout) { @@ -4025,6 +4130,17 @@ dhcp6_fail (NMDevice *self, gboolean timeout) dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) { + /* Don't fail if there are static addresses configured on + * the device, instead retry after some time. + */ + if ( priv->ip6_state == IP_DONE + && priv->con_ip6_config + && nm_ip6_config_get_num_addresses (priv->con_ip6_config)) { + _LOGI (LOGD_DHCP6, "Scheduling DHCPv6 restart because device has IP addresses"); + priv->dhcp6_restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self); + return; + } + if (timeout || (priv->ip6_state == IP_CONF)) nm_device_activate_schedule_ip6_config_timeout (self); else if (priv->ip6_state == IP_DONE) @@ -4074,10 +4190,12 @@ dhcp6_state_changed (NMDhcpClient *client, NMDhcpState state, NMIP6Config *ip6_config, GHashTable *options, + const char *event_id, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + guint i; g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE); g_return_if_fail (!ip6_config || NM_IS_IP6_CONFIG (ip6_config)); @@ -4086,10 +4204,27 @@ dhcp6_state_changed (NMDhcpClient *client, switch (state) { case NM_DHCP_STATE_BOUND: - g_clear_object (&priv->dhcp6_ip6_config); - if (ip6_config) { - priv->dhcp6_ip6_config = g_object_ref (ip6_config); - dhcp6_update_config (self, priv->dhcp6_config, options); + /* If the server sends multiple IPv6 addresses, we receive a state + * changed event for each of them. Use the event ID to merge IPv6 + * addresses from the same transaction into a single configuration. + */ + if ( ip6_config + && event_id + && priv->dhcp6_event_id + && !strcmp (event_id, priv->dhcp6_event_id)) { + for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { + nm_ip6_config_add_address (priv->dhcp6_ip6_config, + nm_ip6_config_get_address (ip6_config, i)); + } + } else { + g_clear_object (&priv->dhcp6_ip6_config); + g_clear_pointer (&priv->dhcp6_event_id, g_free); + if (ip6_config) { + priv->dhcp6_ip6_config = g_object_ref (ip6_config); + priv->dhcp6_event_id = g_strdup (event_id); + dhcp6_update_config (self, priv->dhcp6_config, options); + g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG); + } } if (priv->ip6_state == IP_CONF) { @@ -4182,6 +4317,7 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) g_warn_if_fail (priv->dhcp6_ip6_config == NULL); g_clear_object (&priv->dhcp6_ip6_config); + g_clear_pointer (&priv->dhcp6_event_id, g_free); connection = nm_device_get_connection (self); g_assert (connection); @@ -4437,7 +4573,7 @@ static void nm_device_set_mtu (NMDevice *self, guint32 mtu) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - int ifindex = nm_device_get_ifindex (self); + int ifindex = nm_device_get_ip_ifindex (self); if (mtu) priv->mtu = mtu; @@ -4446,7 +4582,7 @@ nm_device_set_mtu (NMDevice *self, guint32 mtu) if (priv->ip6_mtu) nm_device_ipv6_set_mtu (self, priv->ip6_mtu); - if (priv->mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex)) + if (priv->mtu && priv->mtu != nm_platform_link_get_mtu (NM_PLATFORM_GET, ifindex)) nm_platform_link_set_mtu (NM_PLATFORM_GET, ifindex, priv->mtu); } @@ -4459,20 +4595,20 @@ nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu) priv->ip6_mtu = mtu ?: plat_mtu; - if (priv->ip6_mtu && priv->mtu < priv->ip6_mtu) { - _LOGW (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)", + if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) { + _LOGI (LOGD_DEVICE | LOGD_IP6, "Lowering IPv6 MTU (%d) to match device MTU (%d)", priv->ip6_mtu, priv->mtu); priv->ip6_mtu = priv->mtu; } - if (priv->ip6_mtu < 1280) { - _LOGW (LOGD_DEVICE | LOGD_IP6, "IPv6 MTU (%d) smaller than 1280, adjusting", + if (priv->ip6_mtu && priv->ip6_mtu < 1280) { + _LOGI (LOGD_DEVICE | LOGD_IP6, "IPv6 MTU (%d) smaller than 1280, adjusting", priv->ip6_mtu); priv->ip6_mtu = 1280; } - if (priv->mtu < priv->ip6_mtu) { - _LOGW (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)", + if (priv->ip6_mtu && priv->mtu && priv->mtu < priv->ip6_mtu) { + _LOGI (LOGD_DEVICE | LOGD_IP6, "Raising device MTU (%d) to match IPv6 MTU (%d)", priv->mtu, priv->ip6_mtu); nm_device_set_mtu (self, priv->ip6_mtu); } @@ -5010,11 +5146,6 @@ act_stage3_ip6_config_start (NMDevice *self, ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0) { ret = linklocal6_start (self); - if (ret == NM_ACT_STAGE_RETURN_FINISH) { - /* New blank config; LL address is already in priv->ext_ip6_config */ - *out_config = nm_ip6_config_new (); - g_assert (*out_config); - } } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0) { priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_MANAGED; if (!dhcp6_start (self, TRUE, reason)) { @@ -5903,26 +6034,19 @@ static void _update_ip4_address (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - struct ifreq req; - guint32 new_address; - int fd; - - g_return_if_fail (self != NULL); + guint32 addr; - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGE (LOGD_IP4, "couldn't open control socket."); - return; - } + g_return_if_fail (NM_IS_DEVICE (self)); - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_ip_iface (self), IFNAMSIZ); - if (ioctl (fd, SIOCGIFADDR, &req) == 0) { - new_address = ((struct sockaddr_in *)(&req.ifr_addr))->sin_addr.s_addr; - if (new_address != priv->ip4_address) - priv->ip4_address = new_address; + if ( priv->ip4_config + && ip_config_valid (priv->state) + && nm_ip4_config_get_num_addresses (priv->ip4_config)) { + addr = nm_ip4_config_get_address (priv->ip4_config, 0)->address; + if (addr != priv->ip4_address) { + priv->ip4_address = addr; + g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_ADDRESS); + } } - close (fd); } gboolean @@ -7497,6 +7621,59 @@ nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr) priv->dhcp_anycast_address = g_strdup (addr); } +static void +nm_device_update_metered (NMDevice *self) +{ +#define NM_METERED_INVALID ((NMMetered) -1) + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMSettingConnection *setting; + NMMetered conn_value, value = NM_METERED_INVALID; + NMConnection *connection = NULL; + NMDeviceState state; + + g_return_if_fail (NM_IS_DEVICE (self)); + + state = nm_device_get_state (self); + if ( state <= NM_DEVICE_STATE_DISCONNECTED + || state > NM_DEVICE_STATE_ACTIVATED) + value = NM_METERED_UNKNOWN; + + if (value == NM_METERED_INVALID) { + connection = nm_device_get_connection (self); + if (connection) { + setting = nm_connection_get_setting_connection (connection); + if (setting) { + conn_value = nm_setting_connection_get_metered (setting); + if (conn_value != NM_METERED_UNKNOWN) + value = conn_value; + } + } + } + + /* Try to guess a value using the metered flag in IP configuration */ + if (value == NM_METERED_INVALID) { + if ( priv->ip4_config + && priv->ip4_state == IP_DONE + && nm_ip4_config_get_metered (priv->ip4_config)) + value = NM_METERED_GUESS_YES; + } + + /* Otherwise look at connection type */ + if (value == NM_METERED_INVALID) { + if ( nm_connection_is_type (connection, NM_SETTING_GSM_SETTING_NAME) + || nm_connection_is_type (connection, NM_SETTING_CDMA_SETTING_NAME)) + value = NM_METERED_GUESS_YES; + else + value = NM_METERED_GUESS_NO; + } + + if (value != priv->metered) { + _LOGD (LOGD_DEVICE, "set metered value %d", value); + priv->metered = value; + g_object_notify (G_OBJECT (self), NM_DEVICE_METERED); + } +} + /** * nm_device_check_connection_available(): * @self: the #NMDevice @@ -7856,10 +8033,11 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->default_route.v4_has = FALSE; priv->default_route.v4_is_assumed = TRUE; - priv->default_route.v4_configure_first_time = TRUE; priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; - priv->default_route.v6_configure_first_time = TRUE; + + priv->v4_commit_first_time = TRUE; + priv->v6_commit_first_time = TRUE; nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self); nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self); @@ -7943,9 +8121,11 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean nm_device_master_release_slaves (self); /* slave: mark no longer enslaved */ - g_clear_object (&priv->master); - priv->enslaved = FALSE; - g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER); + if (nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) <= 0) { + g_clear_object (&priv->master); + priv->enslaved = FALSE; + g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER); + } /* Take out any entries in the routing table and any IP address the device had. */ ifindex = nm_device_get_ip_ifindex (self); @@ -7954,6 +8134,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean nm_platform_address_flush (NM_PLATFORM_GET, ifindex); } + nm_device_update_metered (self); _cleanup_generic_post (self, cleanup_type); } @@ -8426,6 +8607,7 @@ _set_state_full (NMDevice *self, break; case NM_DEVICE_STATE_ACTIVATED: _LOGI (LOGD_DEVICE, "Activation: successful, device activated."); + nm_device_update_metered (self); nm_dispatcher_call (DISPATCHER_ACTION_UP, nm_act_request_get_connection (req), self, NULL, NULL, NULL); break; case NM_DEVICE_STATE_FAILED: @@ -8799,9 +8981,10 @@ nm_device_init (NMDevice *self) priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); priv->default_route.v4_is_assumed = TRUE; - priv->default_route.v4_configure_first_time = TRUE; priv->default_route.v6_is_assumed = TRUE; - priv->default_route.v6_configure_first_time = TRUE; + + priv->v4_commit_first_time = TRUE; + priv->v6_commit_first_time = TRUE; } static GObject* @@ -9298,6 +9481,9 @@ get_property (GObject *object, guint prop_id, case PROP_HAS_PENDING_ACTION: g_value_set_boolean (value, nm_device_has_pending_action (self)); break; + case PROP_METERED: + g_value_set_uint (value, priv->metered); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -9561,6 +9747,20 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * NMDevice:metered: + * + * Whether the connection is metered. + * + * Since: 1.0.6 + **/ + g_object_class_install_property + (object_class, PROP_METERED, + g_param_spec_uint (NM_DEVICE_METERED, "", "", + 0, G_MAXUINT32, NM_METERED_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /* Signals */ signals[STATE_CHANGED] = g_signal_new ("state-changed", diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index f1dab9bf..e9d5b948 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -58,6 +58,7 @@ #define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id" #define NM_DEVICE_MTU "mtu" #define NM_DEVICE_HW_ADDRESS "hw-address" +#define NM_DEVICE_METERED "metered" #define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ #define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ @@ -74,7 +75,6 @@ #define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate" #define NM_DEVICE_RECHECK_ASSUME "recheck-assume" - G_BEGIN_DECLS #define NM_TYPE_DEVICE (nm_device_get_type ()) @@ -281,6 +281,7 @@ const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); const char * nm_device_get_type_description (NMDevice *dev); NMDeviceType nm_device_get_device_type (NMDevice *dev); +NMMetered nm_device_get_metered (NMDevice *dev); int nm_device_get_priority (NMDevice *dev); guint32 nm_device_get_ip4_route_metric (NMDevice *dev); diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 23750f35..09b2dd7d 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -40,6 +40,7 @@ #include "nm-enum-types.h" #include "nm-team-enum-types.h" #include "nm-core-internal.h" +#include "nm-ip4-config.h" #include "gsystem-local-alloc.h" #include "nm-device-team-glue.h" @@ -565,6 +566,25 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) } static void +ip4_config_pre_commit (NMDevice *self, NMIP4Config *config) +{ + NMConnection *connection; + NMSettingWired *s_wired; + guint32 mtu; + + connection = nm_device_get_connection (self); + g_assert (connection); + s_wired = nm_connection_get_setting_wired (connection); + + if (s_wired) { + /* MTU override */ + mtu = nm_setting_wired_get_mtu (s_wired); + if (mtu) + nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER); + } +} + +static void deactivate (NMDevice *device) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); @@ -813,6 +833,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) parent_class->master_update_slave_connection = master_update_slave_connection; parent_class->act_stage1_prepare = act_stage1_prepare; + parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->deactivate = deactivate; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 2e116f87..dde743b1 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -55,6 +55,7 @@ #include "nm-dbus-glib-types.h" #include "nm-wifi-enum-types.h" #include "nm-connection-provider.h" +#include "gsystem-local-alloc.h" static gboolean impl_device_get_access_points (NMDeviceWifi *device, @@ -178,7 +179,7 @@ static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface, static void schedule_scanlist_cull (NMDeviceWifi *self); -static gboolean request_wireless_scan (gpointer user_data); +static void request_wireless_scan (NMDeviceWifi *self, GHashTable *scan_options); static void remove_access_point (NMDeviceWifi *device, NMAccessPoint *ap); @@ -753,7 +754,7 @@ deactivate (NMDevice *device) /* Ensure we trigger a scan after deactivating a Hotspot */ if (old_mode == NM_802_11_MODE_AP) { cancel_pending_scan (self); - request_wireless_scan (self); + request_wireless_scan (self, NULL); } } @@ -1253,6 +1254,7 @@ request_scan_cb (NMDevice *device, { NMDeviceWifi *self = NM_DEVICE_WIFI (device); GError *local = NULL; + gs_unref_hashtable GHashTable *new_scan_options = user_data; if (error) { dbus_g_method_return_error (context, error); @@ -1269,7 +1271,7 @@ request_scan_cb (NMDevice *device, } cancel_pending_scan (self); - request_wireless_scan (self); + request_wireless_scan (self, new_scan_options); dbus_g_method_return (context); } @@ -1316,7 +1318,7 @@ impl_device_request_scan (NMDeviceWifi *self, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, request_scan_cb, - NULL); + options ? g_hash_table_ref (options) : NULL); return; error: @@ -1482,23 +1484,31 @@ build_hidden_probe_list (NMDeviceWifi *self) return ssids; } -static gboolean -request_wireless_scan (gpointer user_data) +static void +request_wireless_scan (NMDeviceWifi *self, GHashTable *scan_options) { - NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); gboolean backoff = FALSE; GPtrArray *ssids = NULL; if (priv->requested_scan) { /* There's already a scan in progress */ - return FALSE; + return; } if (check_scanning_allowed (self)) { _LOGD (LOGD_WIFI_SCAN, "scanning requested"); - ssids = build_hidden_probe_list (self); + if (scan_options && g_hash_table_size (scan_options)) { + GValue *val = g_hash_table_lookup (scan_options, "ssids"); + + if (val && G_VALUE_HOLDS (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR)) + ssids = g_ptr_array_ref (g_value_get_boxed (val)); + else + _LOGD (LOGD_WIFI_SCAN, "ignoring invalid scan options"); + } + if (!ssids) + ssids = build_hidden_probe_list (self); if (nm_logging_enabled (LOGL_DEBUG, LOGD_WIFI_SCAN)) { if (ssids) { @@ -1533,9 +1543,14 @@ request_wireless_scan (gpointer user_data) priv->pending_scan_id = 0; schedule_scan (self, backoff); - return FALSE; } +static gboolean +request_wireless_scan_periodic (gpointer user_data) +{ + request_wireless_scan (user_data, NULL); + return FALSE; +} /* * schedule_scan @@ -1563,7 +1578,7 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff) factor = 1; priv->pending_scan_id = g_timeout_add_seconds (next_scan, - request_wireless_scan, + request_wireless_scan_periodic, self); priv->scheduled_scan_time = now + priv->scan_interval; @@ -3072,7 +3087,7 @@ device_state_changed (NMDevice *device, /* Kick off a scan to get latest results */ priv->scan_interval = SCAN_INTERVAL_MIN; cancel_pending_scan (self); - request_wireless_scan (self); + request_wireless_scan (self, NULL); break; default: break; diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index d70dd9a6..1485f4c1 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -79,6 +79,7 @@ enum { PROP_MODE, PROP_MAX_BITRATE, PROP_STRENGTH, + PROP_LAST_SEEN, LAST_PROP }; @@ -195,6 +196,12 @@ get_property (GObject *object, guint prop_id, case PROP_STRENGTH: g_value_set_schar (value, priv->strength); break; + case PROP_LAST_SEEN: + g_value_set_int (value, + priv->last_seen > 0 + ? (gint) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) + : -1); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -294,6 +301,13 @@ nm_ap_class_init (NMAccessPointClass *ap_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_LAST_SEEN, + g_param_spec_int (NM_AP_LAST_SEEN, "", "", + -1, G_MAXINT, -1, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (ap_class), &dbus_glib_nm_access_point_object_info); @@ -1056,7 +1070,7 @@ void nm_ap_set_broadcast (NMAccessPoint *ap, gboolean broadcast) gint32 nm_ap_get_last_seen (const NMAccessPoint *ap) { - g_return_val_if_fail (NM_IS_AP (ap), FALSE); + g_return_val_if_fail (NM_IS_AP (ap), 0); return NM_AP_GET_PRIVATE (ap)->last_seen; } @@ -1064,9 +1078,16 @@ nm_ap_get_last_seen (const NMAccessPoint *ap) void nm_ap_set_last_seen (NMAccessPoint *ap, gint32 last_seen) { + NMAccessPointPrivate *priv; + g_return_if_fail (NM_IS_AP (ap)); - NM_AP_GET_PRIVATE (ap)->last_seen = last_seen; + priv = NM_AP_GET_PRIVATE (ap); + + if (priv->last_seen != last_seen) { + priv->last_seen = last_seen; + g_object_notify (G_OBJECT (ap), NM_AP_LAST_SEEN); + } } gboolean diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 8ad9acb7..67d30769 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -43,6 +43,7 @@ #define NM_AP_MODE "mode" #define NM_AP_MAX_BITRATE "max-bitrate" #define NM_AP_STRENGTH "strength" +#define NM_AP_LAST_SEEN "last-seen" typedef struct { GObject parent; |