aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2018-06-25 06:05:14 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2018-06-25 16:42:30 +0200
commite336e49df3e63ff6ff0e101a4803bf6c0f9a3e02 (patch)
tree84a1be70b4af5fa4b8a82660dbd9c112e04ac584
parentwg-quick: android: prevent outgoing handshake packets from being dropped (diff)
downloadWireGuard-jd/android-suspend-xmit.tar.xz
WireGuard-jd/android-suspend-xmit.zip
send: wait for suspend to complete before sending handshakejd/android-suspend-xmit
Otherwise the transmission might be dropped on Android devices.
-rw-r--r--src/device.c58
-rw-r--r--src/device.h5
-rw-r--r--src/send.c6
3 files changed, 47 insertions, 22 deletions
diff --git a/src/device.c b/src/device.c
index df9189b..5f5ef8b 100644
--- a/src/device.c
+++ b/src/device.c
@@ -67,31 +67,44 @@ static int open(struct net_device *dev)
return 0;
}
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_ANDROID)
+#ifdef CONFIG_PM_SLEEP
+static DECLARE_COMPLETION(pm_awake);
+void device_wait_for_awake(void)
+{
+ wait_for_completion(&pm_awake);
+}
static int pm_notification(struct notifier_block *nb, unsigned long action, void *data)
{
- struct wireguard_device *wg;
- struct wireguard_peer *peer;
-
- if (action != PM_HIBERNATION_PREPARE && action != PM_SUSPEND_PREPARE)
- return 0;
-
- rtnl_lock();
- list_for_each_entry(wg, &device_list, device_list) {
- mutex_lock(&wg->device_update_lock);
- list_for_each_entry(peer, &wg->peer_list, peer_list) {
- noise_handshake_clear(&peer->handshake);
- noise_keypairs_clear(&peer->keypairs);
- if (peer->timers_enabled)
- del_timer(&peer->timer_zero_key_material);
+ switch (action) {
+ case PM_HIBERNATION_PREPARE:
+ case PM_SUSPEND_PREPARE: {
+#ifndef CONFIG_ANDROID
+ struct wireguard_device *wg;
+ struct wireguard_peer *peer;
+ rtnl_lock();
+ list_for_each_entry(wg, &device_list, device_list) {
+ mutex_lock(&wg->device_update_lock);
+ list_for_each_entry(peer, &wg->peer_list, peer_list) {
+ noise_handshake_clear(&peer->handshake);
+ noise_keypairs_clear(&peer->keypairs);
+ if (peer->timers_enabled)
+ del_timer(&peer->timer_zero_key_material);
+ }
+ mutex_unlock(&wg->device_update_lock);
}
- mutex_unlock(&wg->device_update_lock);
+ rtnl_unlock();
+ rcu_barrier_bh();
+#endif
+ reinit_completion(&pm_awake);
}
- rtnl_unlock();
- rcu_barrier_bh();
+ case PM_POST_HIBERNATION:
+ case PM_POST_SUSPEND:
+ complete_all(&pm_awake);
+ }
+
return 0;
}
-static struct notifier_block pm_notifier = { .notifier_call = pm_notification };
+static struct notifier_block pm_notifier = { .notifier_call = pm_notification, .priority = INT_MIN };
#endif
static int stop(struct net_device *dev)
@@ -390,7 +403,8 @@ int __init device_init(void)
{
int ret;
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_ANDROID)
+#ifdef CONFIG_PM_SLEEP
+ complete_all(&pm_awake);
ret = register_pm_notifier(&pm_notifier);
if (ret)
return ret;
@@ -409,7 +423,7 @@ int __init device_init(void)
error_netdevice:
unregister_netdevice_notifier(&netdevice_notifier);
error_pm:
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_ANDROID)
+#ifdef CONFIG_PM_SLEEP
unregister_pm_notifier(&pm_notifier);
#endif
return ret;
@@ -419,7 +433,7 @@ void device_uninit(void)
{
rtnl_link_unregister(&link_ops);
unregister_netdevice_notifier(&netdevice_notifier);
-#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_ANDROID)
+#ifdef CONFIG_PM_SLEEP
unregister_pm_notifier(&pm_notifier);
#endif
rcu_barrier_bh();
diff --git a/src/device.h b/src/device.h
index 2a0e2c7..da8a72a 100644
--- a/src/device.h
+++ b/src/device.h
@@ -60,5 +60,10 @@ struct wireguard_device {
int device_init(void);
void device_uninit(void);
+#if defined(CONFIG_PM_SLEEP)
+void device_wait_for_awake(void);
+#else
+static inline void device_wait_for_awake(void) { }
+#endif
#endif /* _WG_DEVICE_H */
diff --git a/src/send.c b/src/send.c
index 7a8bea1..0b3ff48 100644
--- a/src/send.c
+++ b/src/send.c
@@ -31,6 +31,8 @@ static void packet_send_handshake_initiation(struct wireguard_peer *peer)
peer->last_sent_handshake = ktime_get_boot_fast_ns();
up_write(&peer->handshake.lock);
+ device_wait_for_awake();
+
net_dbg_ratelimited("%s: Sending handshake initiation to peer %llu (%pISpfsc)\n", peer->device->dev->name, peer->internal_id, &peer->endpoint.addr);
if (noise_handshake_create_initiation(&packet, &peer->handshake)) {
@@ -71,6 +73,8 @@ void packet_send_handshake_response(struct wireguard_peer *peer)
{
struct message_handshake_response packet;
+ device_wait_for_awake();
+
net_dbg_ratelimited("%s: Sending handshake response to peer %llu (%pISpfsc)\n", peer->device->dev->name, peer->internal_id, &peer->endpoint.addr);
peer->last_sent_handshake = ktime_get_boot_fast_ns();
@@ -89,6 +93,8 @@ void packet_send_handshake_cookie(struct wireguard_device *wg, struct sk_buff *i
{
struct message_handshake_cookie packet;
+ device_wait_for_awake();
+
net_dbg_skb_ratelimited("%s: Sending cookie response for denied handshake message for %pISpfsc\n", wg->dev->name, initiating_skb);
cookie_message_create(&packet, initiating_skb, sender_index, &wg->cookie_checker);
socket_send_buffer_as_reply_to_skb(wg, initiating_skb, &packet, sizeof(packet));