Dan Winship 2014-04-17 12:48:38 -04:00
commit 8d9ddbee17
9 changed files with 154 additions and 12 deletions

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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)
{

View file

@ -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);