+
+// hasFallenBack reports whether the MPTCP connection has fallen back to "plain"
+// TCP.
+//
+// A connection can fallback to TCP for different reasons, e.g. the other peer
+// doesn't support it, a middle box "accidentally" drops the option, etc.
+//
+// If the MPTCP protocol has not been requested when creating the socket, this
+// method will return true: MPTCP is not being used.
+//
+// Kernel >= 5.16 returns EOPNOTSUPP/ENOPROTOOPT in case of fallback.
+// Older kernels will always return them even if MPTCP is used: not usable.
+func hasFallenBack(fd *netFD) bool {
+ _, err := fd.pfd.GetsockoptInt(_SOL_MPTCP, _MPTCP_INFO)
+
+ // 2 expected errors in case of fallback depending on the address family
+ // - AF_INET: EOPNOTSUPP
+ // - AF_INET6: ENOPROTOOPT
+ return err == syscall.EOPNOTSUPP || err == syscall.ENOPROTOOPT
+}
+
+// isUsingMPTCPProto reports whether the socket protocol is MPTCP.
+//
+// Compared to hasFallenBack method, here only the socket protocol being used is
+// checked: it can be MPTCP but it doesn't mean MPTCP is used on the wire, maybe
+// a fallback to TCP has been done.
+func isUsingMPTCPProto(fd *netFD) bool {
+ proto, _ := fd.pfd.GetsockoptInt(syscall.SOL_SOCKET, syscall.SO_PROTOCOL)
+
+ return proto == _IPPROTO_MPTCP
+}
+
+// isUsingMultipathTCP reports whether MPTCP is still being used.
+//
+// Please look at the description of hasFallenBack (kernel >=5.16) and
+// isUsingMPTCPProto methods for more details about what is being checked here.
+func isUsingMultipathTCP(fd *netFD) bool {
+ if hasSOLMPTCP {
+ return !hasFallenBack(fd)
+ }
+
+ return isUsingMPTCPProto(fd)
+}