diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index 291e2e5bb450..306c7b3200a7 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -254,15 +254,6 @@ static int ovpn_nl_peer_precheck(struct ovpn_priv *ovpn,
 		return -EINVAL;
 	}
 
-	if ((attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL] &&
-	     !attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]) ||
-	    (!attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL] &&
-	     attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT])) {
-		NL_SET_ERR_MSG_FMT_MOD(info->extack,
-				       "keepalive interval and timeout are required together");
-		return -EINVAL;
-	}
-
 	return 0;
 }
 
@@ -281,7 +272,6 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,
 {
 	struct sockaddr_storage ss = {};
 	void *local_ip = NULL;
-	u32 interv, timeout;
 	bool rehash = false;
 	int ret;
 
@@ -323,13 +313,9 @@ static int ovpn_nl_peer_modify(struct ovpn_peer *peer, struct genl_info *info,
 			nla_get_in6_addr(attrs[OVPN_A_PEER_VPN_IPV6]);
 	}
 
-	/* when setting the keepalive, both parameters have to be configured */
-	if (attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL] &&
-	    attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]) {
-		interv = nla_get_u32(attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL]);
-		timeout = nla_get_u32(attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]);
-		ovpn_peer_keepalive_set(peer, interv, timeout);
-	}
+	ovpn_peer_keepalive_set(peer,
+				attrs[OVPN_A_PEER_KEEPALIVE_INTERVAL],
+				attrs[OVPN_A_PEER_KEEPALIVE_TIMEOUT]);
 
 	netdev_dbg(peer->ovpn->dev,
 		   "modify peer id=%u tx_id=%u endpoint=%pIScp VPN-IPv4=%pI4 VPN-IPv6=%pI6c\n",
diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
index c02dfab51a6e..b06dbd8feb0b 100644
--- a/drivers/net/ovpn/peer.c
+++ b/drivers/net/ovpn/peer.c
@@ -37,26 +37,60 @@ static void unlock_ovpn(struct ovpn_priv *ovpn,
 }
 
 /**
- * ovpn_peer_keepalive_set - configure keepalive values for peer
+ * ovpn_peer_keepalive_interval_set - configure keepalive interval for peer
  * @peer: the peer to configure
  * @interval: outgoing keepalive interval
- * @timeout: incoming keepalive timeout
+ * @now: current time
  */
-void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout)
+static void ovpn_peer_keepalive_interval_set(struct ovpn_peer *peer, u32 interval, time64_t now)
 {
-	time64_t now = ktime_get_real_seconds();
-
 	netdev_dbg(peer->ovpn->dev,
-		   "scheduling keepalive for peer %u: interval=%u timeout=%u\n",
-		   peer->id, interval, timeout);
+		   "scheduling keepalive interval for peer %u: %u\n",
+		   peer->id, interval);
 
 	peer->keepalive_interval = interval;
 	WRITE_ONCE(peer->last_sent, now);
 	peer->keepalive_xmit_exp = now + interval;
+}
+
+/**
+ * ovpn_peer_keepalive_timeout_set - configure keepalive timeout for peer
+ * @peer: the peer to configure
+ * @timeout: incoming keepalive timeout
+ * @now: current time
+ */
+static void ovpn_peer_keepalive_timeout_set(struct ovpn_peer *peer, u32 timeout, time64_t now)
+{
+	netdev_dbg(peer->ovpn->dev,
+		   "scheduling keepalive timeout for peer %u: %u\n",
+		   peer->id, timeout);
 
 	peer->keepalive_timeout = timeout;
 	WRITE_ONCE(peer->last_recv, now);
 	peer->keepalive_recv_exp = now + timeout;
+}
+
+/**
+ * ovpn_peer_keepalive_set - configure keepalive values for peer
+ * @peer: the peer to configure
+ * @nla_interval: pointer to the KEEPALIVE_INTERVAL netlink attribute
+ * @nla_timeout: pointer to the KEEPALIVE_TIMEOUT netlink attribute
+ */
+void ovpn_peer_keepalive_set(struct ovpn_peer *peer,
+			     const struct nlattr *nla_interval,
+			     const struct nlattr *nla_timeout)
+{
+	time64_t now;
+
+	if (!nla_interval && !nla_timeout)
+		return;
+
+	now = ktime_get_real_seconds();
+
+	if (nla_interval)
+		ovpn_peer_keepalive_interval_set(peer, nla_get_u32(nla_interval), now);
+	if (nla_timeout)
+		ovpn_peer_keepalive_timeout_set(peer, nla_get_u32(nla_timeout), now);
 
 	/* now that interval and timeout have been changed, kick
 	 * off the worker so that the next delay can be recomputed
@@ -1214,15 +1248,13 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
 						time64_t now,
 						struct llist_head *release_list)
 {
-	time64_t last_recv, last_sent, next_run1, next_run2;
+	time64_t last_recv, last_sent, next_run1 = 0, next_run2;
 	unsigned long timeout, interval;
 	bool expired;
 
 	spin_lock_bh(&peer->lock);
-	/* we expect both timers to be configured at the same time,
-	 * therefore bail out if either is not set
-	 */
-	if (!peer->keepalive_timeout || !peer->keepalive_interval) {
+
+	if (!peer->keepalive_timeout && !peer->keepalive_interval) {
 		spin_unlock_bh(&peer->lock);
 		return 0;
 	}
@@ -1230,31 +1262,33 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
 	/* check for peer timeout */
 	expired = false;
 	timeout = peer->keepalive_timeout;
-	last_recv = READ_ONCE(peer->last_recv);
-	if (now < last_recv + timeout) {
-		peer->keepalive_recv_exp = last_recv + timeout;
-		next_run1 = peer->keepalive_recv_exp;
-	} else if (peer->keepalive_recv_exp > now) {
-		next_run1 = peer->keepalive_recv_exp;
-	} else {
-		expired = true;
-	}
+	if (timeout) {
+		last_recv = READ_ONCE(peer->last_recv);
+		if (now < last_recv + timeout) {
+			peer->keepalive_recv_exp = last_recv + timeout;
+			next_run1 = peer->keepalive_recv_exp;
+		} else if (peer->keepalive_recv_exp > now) {
+			next_run1 = peer->keepalive_recv_exp;
+		} else {
+			expired = true;
+		}
 
-	if (expired) {
-		/* peer is dead -> kill it and move on */
-		spin_unlock_bh(&peer->lock);
-		netdev_dbg(peer->ovpn->dev, "peer %u expired\n",
-			   peer->id);
-		ovpn_peer_remove(peer, OVPN_DEL_PEER_REASON_EXPIRED,
-				 release_list);
-		return 0;
+		if (expired) {
+			/* peer is dead -> kill it and move on */
+			spin_unlock_bh(&peer->lock);
+			netdev_dbg(peer->ovpn->dev, "peer %u expired\n", peer->id);
+			ovpn_peer_remove(peer, OVPN_DEL_PEER_REASON_EXPIRED, release_list);
+			return 0;
+		}
 	}
 
 	/* check for peer keepalive */
-	expired = false;
 	interval = peer->keepalive_interval;
 	last_sent = READ_ONCE(peer->last_sent);
-	if (now < last_sent + interval) {
+	if (!interval) {
+		spin_unlock_bh(&peer->lock);
+		return next_run1;
+	} else if (now < last_sent + interval) {
 		peer->keepalive_xmit_exp = last_sent + interval;
 		next_run2 = peer->keepalive_xmit_exp;
 	} else if (peer->keepalive_xmit_exp > now) {
@@ -1274,7 +1308,7 @@ static time64_t ovpn_peer_keepalive_work_single(struct ovpn_peer *peer,
 			ovpn_peer_hold(peer);
 	}
 
-	if (next_run1 < next_run2)
+	if (next_run1 && next_run1 < next_run2)
 		return next_run1;
 
 	return next_run2;
diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h
index 328401570cba..af184a3aca80 100644
--- a/drivers/net/ovpn/peer.h
+++ b/drivers/net/ovpn/peer.h
@@ -154,7 +154,9 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer);
 bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb,
 			    struct ovpn_peer *peer);
 
-void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout);
+void ovpn_peer_keepalive_set(struct ovpn_peer *peer,
+			     const struct nlattr *nla_interval,
+			     const struct nlattr *nla_timeout);
 void ovpn_peer_keepalive_work(struct work_struct *work);
 
 void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb);
