mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-09 13:10:39 +01:00
core: don't break Wake-on-LAN
https://bugzilla.gnome.org/show_bug.cgi?id=712745 https://bugzilla.redhat.com/show_bug.cgi?id=826652 https://bugzilla.redhat.com/show_bug.cgi?id=1025009
This commit is contained in:
commit
8d9ddbee17
9 changed files with 154 additions and 12 deletions
|
|
@ -3589,27 +3589,56 @@ done:
|
|||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
device_is_wake_on_lan (NMDevice *device)
|
||||
{
|
||||
return nm_platform_link_get_wake_on_lan (nm_device_get_ip_ifindex (device));
|
||||
}
|
||||
|
||||
static void
|
||||
do_sleep_wake (NMManager *self)
|
||||
do_sleep_wake (NMManager *self, gboolean sleeping_changed)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
gboolean suspending, waking_from_suspend;
|
||||
GSList *iter;
|
||||
|
||||
if (manager_sleeping (self)) {
|
||||
nm_log_info (LOGD_SUSPEND, "sleeping or disabling...");
|
||||
suspending = sleeping_changed && priv->sleeping;
|
||||
waking_from_suspend = sleeping_changed && !priv->sleeping;
|
||||
|
||||
/* Just deactivate and down all physical devices from the device list,
|
||||
* to keep things fast the device list will get resynced when
|
||||
* the manager wakes up.
|
||||
if (manager_sleeping (self)) {
|
||||
nm_log_info (LOGD_SUSPEND, suspending ? "sleeping..." : "disabling...");
|
||||
|
||||
/* FIXME: are there still hardware devices that need to be disabled around
|
||||
* suspend/resume?
|
||||
*/
|
||||
for (iter = priv->devices; iter; iter = iter->next) {
|
||||
NMDevice *device = iter->data;
|
||||
|
||||
if (!nm_device_is_software (device))
|
||||
nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
|
||||
/* FIXME: shouldn't we be unmanaging software devices if !suspending? */
|
||||
if (nm_device_is_software (device))
|
||||
continue;
|
||||
/* Wake-on-LAN devices will be taken down post-suspend rather than pre- */
|
||||
if (suspending && device_is_wake_on_lan (device))
|
||||
continue;
|
||||
|
||||
nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
|
||||
}
|
||||
} else {
|
||||
nm_log_info (LOGD_SUSPEND, "waking up and re-enabling...");
|
||||
nm_log_info (LOGD_SUSPEND, waking_from_suspend ? "waking up..." : "re-enabling...");
|
||||
|
||||
if (waking_from_suspend) {
|
||||
/* Belatedly take down Wake-on-LAN devices; ideally we wouldn't have to do this
|
||||
* but for now it's the only way to make sure we re-check their connectivity.
|
||||
*/
|
||||
for (iter = priv->devices; iter; iter = iter->next) {
|
||||
NMDevice *device = iter->data;
|
||||
|
||||
if (nm_device_is_software (device))
|
||||
continue;
|
||||
if (device_is_wake_on_lan (device))
|
||||
nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure rfkill state is up-to-date since we don't respond to state
|
||||
* changes during sleep.
|
||||
|
|
@ -3665,7 +3694,7 @@ _internal_sleep (NMManager *self, gboolean do_sleep)
|
|||
|
||||
priv->sleeping = do_sleep;
|
||||
|
||||
do_sleep_wake (self);
|
||||
do_sleep_wake (self, TRUE);
|
||||
|
||||
g_object_notify (G_OBJECT (self), NM_MANAGER_SLEEPING);
|
||||
}
|
||||
|
|
@ -3805,7 +3834,7 @@ _internal_enable (NMManager *self, gboolean enable)
|
|||
|
||||
priv->net_enabled = enable;
|
||||
|
||||
do_sleep_wake (self);
|
||||
do_sleep_wake (self, FALSE);
|
||||
|
||||
g_object_notify (G_OBJECT (self), NM_MANAGER_NETWORKING_ENABLED);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,6 +476,15 @@ link_get_physical_port_id (NMPlatform *platform, int ifindex)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_get_wake_on_lan (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
/* We call link_get just to cause an error to be set if @ifindex is bad. */
|
||||
link_get (platform, ifindex);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
|
|
@ -1301,6 +1310,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
|||
platform_class->link_set_mtu = link_set_mtu;
|
||||
|
||||
platform_class->link_get_physical_port_id = link_get_physical_port_id;
|
||||
platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
|
||||
|
||||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||||
platform_class->link_supports_vlans = link_supports_vlans;
|
||||
|
|
|
|||
|
|
@ -2873,6 +2873,31 @@ mesh_set_ssid (NMPlatform *platform, int ifindex, const GByteArray *ssid)
|
|||
return wifi_utils_set_mesh_ssid (wifi_data, ssid);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_get_wake_on_lan (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
NMLinkType type = link_get_type (platform, ifindex);
|
||||
|
||||
if (type == NM_LINK_TYPE_ETHERNET) {
|
||||
struct ethtool_wolinfo wol;
|
||||
|
||||
memset (&wol, 0, sizeof (wol));
|
||||
wol.cmd = ETHTOOL_GWOL;
|
||||
if (!ethtool_get (link_get_name (platform, ifindex), &wol))
|
||||
return FALSE;
|
||||
|
||||
return wol.wolopts != 0;
|
||||
} else if (type == NM_LINK_TYPE_WIFI) {
|
||||
WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex);
|
||||
|
||||
if (!wifi_data)
|
||||
return FALSE;
|
||||
|
||||
return wifi_utils_get_wowlan (wifi_data);
|
||||
} else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static int
|
||||
|
|
@ -3644,6 +3669,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||
platform_class->link_set_mtu = link_set_mtu;
|
||||
|
||||
platform_class->link_get_physical_port_id = link_get_physical_port_id;
|
||||
platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
|
||||
|
||||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||||
platform_class->link_supports_vlans = link_supports_vlans;
|
||||
|
|
|
|||
|
|
@ -901,6 +901,23 @@ nm_platform_link_get_physical_port_id (int ifindex)
|
|||
return klass->link_get_physical_port_id (platform, ifindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_get_wake_onlan:
|
||||
* @ifindex: Interface index
|
||||
*
|
||||
* Returns: the "Wake-on-LAN" status for @ifindex.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_link_get_wake_on_lan (int ifindex)
|
||||
{
|
||||
reset_error ();
|
||||
|
||||
g_return_val_if_fail (ifindex >= 0, FALSE);
|
||||
g_return_val_if_fail (klass->link_get_wake_on_lan, FALSE);
|
||||
|
||||
return klass->link_get_wake_on_lan (platform, ifindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_enslave:
|
||||
* @master: Interface index of the master
|
||||
|
|
|
|||
|
|
@ -321,6 +321,7 @@ typedef struct {
|
|||
gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
|
||||
|
||||
char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex);
|
||||
|
||||
gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
|
||||
|
|
@ -466,7 +467,8 @@ gboolean nm_platform_link_set_address (int ifindex, const void *address, size_t
|
|||
guint32 nm_platform_link_get_mtu (int ifindex);
|
||||
gboolean nm_platform_link_set_mtu (int ifindex, guint32 mtu);
|
||||
|
||||
char *nm_platform_link_get_physical_port_id (int ifindex);
|
||||
char *nm_platform_link_get_physical_port_id (int ifindex);
|
||||
gboolean nm_platform_link_get_wake_on_lan (int ifindex);
|
||||
|
||||
gboolean nm_platform_link_supports_carrier_detect (int ifindex);
|
||||
gboolean nm_platform_link_supports_vlans (int ifindex);
|
||||
|
|
|
|||
|
|
@ -604,6 +604,43 @@ nla_put_failure:
|
|||
}
|
||||
#endif
|
||||
|
||||
struct nl80211_wowlan_info {
|
||||
gboolean enabled;
|
||||
};
|
||||
|
||||
static int
|
||||
nl80211_wowlan_handler (struct nl_msg *msg, void *arg)
|
||||
{
|
||||
struct nlattr *tb[NL80211_ATTR_MAX + 1];
|
||||
struct genlmsghdr *gnlh = nlmsg_data (nlmsg_hdr (msg));
|
||||
struct nl80211_wowlan_info *info = arg;
|
||||
|
||||
info->enabled = FALSE;
|
||||
|
||||
if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
|
||||
genlmsg_attrlen (gnlh, 0), NULL) < 0)
|
||||
return NL_SKIP;
|
||||
|
||||
if (tb[NL80211_ATTR_WOWLAN_TRIGGERS])
|
||||
info->enabled = TRUE;
|
||||
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wifi_nl80211_get_wowlan (WifiData *data)
|
||||
{
|
||||
WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data;
|
||||
struct nl_msg *msg;
|
||||
struct nl80211_wowlan_info info;
|
||||
|
||||
msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_WOWLAN, 0);
|
||||
|
||||
nl80211_send_and_recv (nl80211, msg, nl80211_wowlan_handler, &info);
|
||||
|
||||
return info.enabled;
|
||||
}
|
||||
|
||||
struct nl80211_device_info {
|
||||
guint32 *freqs;
|
||||
int num_freqs;
|
||||
|
|
@ -612,6 +649,7 @@ struct nl80211_device_info {
|
|||
gboolean can_scan_ssid;
|
||||
gboolean supported;
|
||||
gboolean success;
|
||||
gboolean can_wowlan;
|
||||
};
|
||||
|
||||
#define WLAN_CIPHER_SUITE_USE_GROUP 0x000FAC00
|
||||
|
|
@ -770,6 +808,9 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
if (tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED])
|
||||
info->can_wowlan = TRUE;
|
||||
|
||||
info->success = TRUE;
|
||||
|
||||
return NL_SKIP;
|
||||
|
|
@ -860,6 +901,9 @@ wifi_nl80211_init (const char *iface, int ifindex)
|
|||
nl80211->num_freqs = device_info.num_freqs;
|
||||
nl80211->parent.caps = device_info.caps;
|
||||
|
||||
if (device_info.can_wowlan)
|
||||
nl80211->parent.get_wowlan = wifi_nl80211_get_wowlan;
|
||||
|
||||
nm_log_info (LOGD_HW | LOGD_WIFI,
|
||||
"(%s): using nl80211 for WiFi device control",
|
||||
nl80211->parent.iface);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ struct WifiData {
|
|||
|
||||
void (*deinit) (WifiData *data);
|
||||
|
||||
gboolean (*get_wowlan) (WifiData *data);
|
||||
|
||||
/* OLPC Mesh-only functions */
|
||||
|
||||
guint32 (*get_mesh_channel) (WifiData *data);
|
||||
|
|
|
|||
|
|
@ -143,6 +143,15 @@ wifi_utils_get_qual (WifiData *data)
|
|||
return data->get_qual (data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
wifi_utils_get_wowlan (WifiData *data)
|
||||
{
|
||||
g_return_val_if_fail (data != NULL, 0);
|
||||
if (!data->get_wowlan)
|
||||
return FALSE;
|
||||
return data->get_wowlan (data);
|
||||
}
|
||||
|
||||
void
|
||||
wifi_utils_deinit (WifiData *data)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ int wifi_utils_get_qual (WifiData *data);
|
|||
/* Tells the driver DHCP or SLAAC is running */
|
||||
gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean running);
|
||||
|
||||
/* Returns true if WoWLAN is enabled on device */
|
||||
gboolean wifi_utils_get_wowlan (WifiData *data);
|
||||
|
||||
|
||||
/* OLPC Mesh-only functions */
|
||||
guint32 wifi_utils_get_mesh_channel (WifiData *data);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue