+
+ /* Make sure we get both IPv4 and IPv6 connections.
+ * This is the default, but it can be overridden so we
+ * force it back.
+ */
+#ifdef HAVE_KERNEL_SETSOCKOPT
+ kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
+ (char *) &val, sizeof(val));
+#elif defined(_LINUX_SOCKPTR_H)
+ /* sockptr_t was introduced around
+ * v5.8-rc4-1952-ga7b75c5a8c41 and allows a
+ * kernel address to be passed to ->setsockopt
+ */
+ if (ipv6_only_sock(sock->sk)) {
+ sockptr_t optval = KERNEL_SOCKPTR(&val);
+
+ sock->ops->setsockopt(sock,
+ IPPROTO_IPV6, IPV6_V6ONLY,
+ optval, sizeof(val));
+ }
+#else
+ /* From v5.7-rc6-2614-g5a892ff2facb when
+ * kernel_setsockopt() was removed until
+ * sockptr_t (above) there is no clean way to
+ * pass kernel address to setsockopt. We could
+ * use get_fs()/set_fs(), but in this particular
+ * situation there is an easier way. It depends
+ * on the fact that at least for these few
+ * kernels a NULL address to ipv6_setsockopt()
+ * is treated like the address of a zero.
+ */
+ if (ipv6_only_sock(sock->sk) && !val) {
+ void *optval = NULL;
+
+ sock->ops->setsockopt(sock,
+ IPPROTO_IPV6, IPV6_V6ONLY,
+ optval, sizeof(val));
+ }
+#endif /* HAVE_KERNEL_SETSOCKOPT */
+