diff --git a/compat/compat.h b/compat/compat.h
index 3be1113..f5437cc 100644
--- a/compat/compat.h
+++ b/compat/compat.h
@@ -1444,4 +1444,23 @@ static inline void __compat_chacha20_crypt(struct chacha_state *state,
 
 #endif
 
+/*
+* API break in 7.2, backported to 7.1.5 but no other stable series
+* https://github.com/torvalds/linux/commit/2cba193628fe523cee6dd61938db2c4563ce15a9
+* https://github.com/torvalds/linux/commit/944bfc1b1c6fe9417668006aae7124886bcca038
+*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(7, 1, 5)
+#include <net/udp_tunnel.h>
+#define setup_udp_tunnel_sock(net, sk, sock_cfg) setup_udp_tunnel_sock(net, sk->sk_socket, sock_cfg)
+#define udp_tunnel_sock_release(sk) udp_tunnel_sock_release(sk->sk_socket)
+#endif
+
+/*
+* WQ_PERCPU introduced in 6.18, not passing it is deprecated and causes a splat in 7.2
+* https://github.com/torvalds/linux/commit/21c05ca88a548ca1353cbef189c97d4f03b90692
+*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 18, 0)
+#define WQ_PERCPU 0
+#endif
+
 #endif /* _WG_COMPAT_H */
diff --git a/device.c b/device.c
index c8f4312..011e718 100644
--- a/device.c
+++ b/device.c
@@ -379,7 +379,7 @@ static int wg_newlink(struct net_device *dev,
 #endif
 
 	wg->handshake_receive_wq = alloc_workqueue("wg-kex-%s",
-			WQ_CPU_INTENSIVE | WQ_FREEZABLE, 0, dev->name);
+			WQ_CPU_INTENSIVE | WQ_FREEZABLE | WQ_PERCPU, 0, dev->name);
 	if (!wg->handshake_receive_wq)
 		goto err_free_tstats;
 
@@ -389,7 +389,7 @@ static int wg_newlink(struct net_device *dev,
 		goto err_destroy_handshake_receive;
 
 	wg->packet_crypt_wq = alloc_workqueue("wg-crypt-%s",
-			WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 0, dev->name);
+			WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_PERCPU, 0, dev->name);
 	if (!wg->packet_crypt_wq)
 		goto err_destroy_handshake_send;
 
diff --git a/netlink.c b/netlink.c
index b1da877..28f1efa 100644
--- a/netlink.c
+++ b/netlink.c
@@ -172,8 +172,8 @@ static inline int parse_ipv4_prefix(const char *prefix_str, struct ipv4_prefix *
 	if (slash - prefix_str >= INET_ADDRSTRLEN)
 		return -EINVAL;
 
-	strncpy(addr_str, prefix_str, slash - prefix_str);
-	addr_str[slash - prefix_str] = '\0';
+	// strscpy count includes null terminator
+	strscpy(addr_str, prefix_str, slash - prefix_str + 1);
 
 	ret = kstrtoint(slash + 1, 10, &prefix->prefix_len);
 	if (ret < 0)
@@ -231,8 +231,8 @@ static inline int parse_ipv6_prefix(const char *prefix_str, struct ipv6_prefix *
 	if (slash - prefix_str >= INET6_ADDRSTRLEN)
 		return -EINVAL;
 
-	strncpy(addr_str, prefix_str, slash - prefix_str);
-	addr_str[slash - prefix_str] = '\0';
+	// strscpy count includes null terminator
+	strscpy(addr_str, prefix_str, slash - prefix_str + 1);
 
 	ret = kstrtoint(slash + 1, 10, &prefix->prefix_len);
 	if (ret < 0)
diff --git a/socket.c b/socket.c
index 24bf1ab..a84bdb2 100644
--- a/socket.c
+++ b/socket.c
@@ -375,7 +375,7 @@ static void sock_free(struct sock *sock)
 	if (unlikely(!sock))
 		return;
 	sk_clear_memalloc(sock);
-	udp_tunnel_sock_release(sock->sk_socket);
+	udp_tunnel_sock_release(sock);
 }
 
 static void set_sock_opts(struct socket *sock)
@@ -429,14 +429,14 @@ retry:
 		goto out;
 	}
 	set_sock_opts(new4);
-	setup_udp_tunnel_sock(net, new4, &cfg);
+	setup_udp_tunnel_sock(net, new4->sk, &cfg);
 
 #if IS_ENABLED(CONFIG_IPV6)
 	if (ipv6_mod_enabled()) {
 		port6.local_udp_port = inet_sk(new4->sk)->inet_sport;
 		ret = udp_sock_create(net, &port6, &new6);
 		if (ret < 0) {
-			udp_tunnel_sock_release(new4);
+			udp_tunnel_sock_release(new4->sk);
 			if (ret == -EADDRINUSE && !port && retries++ < 100)
 				goto retry;
 			pr_err("%s: Could not create IPv6 socket\n",
@@ -444,7 +444,7 @@ retry:
 			goto out;
 		}
 		set_sock_opts(new6);
-		setup_udp_tunnel_sock(net, new6, &cfg);
+		setup_udp_tunnel_sock(net, new6->sk, &cfg);
 	}
 #endif
 
