Test to check tcp initial rwnd size

The backport for 4.19 kernel sets the initial receive window size to a
new value greater then 64k. Use a connected TCP socket to check the
patch is properly applied.

Test: ./sock_diag_test.py
Bug: 118591209
Change-Id: If21c6e951aede70c22699d1794dbc09ce91ba5e4
diff --git a/net/test/sock_diag_test.py b/net/test/sock_diag_test.py
index b195fe3..daa2fa4 100755
--- a/net/test/sock_diag_test.py
+++ b/net/test/sock_diag_test.py
@@ -25,16 +25,20 @@
 import time
 import unittest
 
+import cstruct
 import multinetwork_base
 import net_test
 import packets
 import sock_diag
 import tcp_test
 
+# Mostly empty structure definition containing only the fields we currently use.
+TcpInfo = cstruct.Struct("TcpInfo", "64xI", "tcpi_rcv_ssthresh")
 
 NUM_SOCKETS = 30
 NO_BYTECODE = ""
-HAVE_SO_COOKIE_SUPPORT = net_test.LINUX_VERSION >= (4, 9, 0)
+LINUX_4_9_OR_ABOVE = net_test.LINUX_VERSION >= (4, 9, 0)
+LINUX_4_19_OR_ABOVE = net_test.LINUX_VERSION >= (4, 19, 0)
 
 IPPROTO_SCTP = 132
 
@@ -55,7 +59,7 @@
     True if the kernel is 4.9 or above, or the CONFIG_INET_UDP_DIAG is enabled.
     False otherwise.
   """
-  if HAVE_SO_COOKIE_SUPPORT:
+  if LINUX_4_9_OR_ABOVE:
       return True;
   s = socket(AF_INET6, SOCK_DGRAM, 0)
   s.bind(("::", 0))
@@ -386,7 +390,7 @@
       cookie = sock.getsockopt(net_test.SOL_SOCKET, net_test.SO_COOKIE, 8)
       self.assertEqual(diag_msg.id.cookie, cookie)
 
-  @unittest.skipUnless(HAVE_SO_COOKIE_SUPPORT, "SO_COOKIE not supported")
+  @unittest.skipUnless(LINUX_4_9_OR_ABOVE, "SO_COOKIE not supported")
   def testGetsockoptcookie(self):
     self.CheckSocketCookie(AF_INET, "127.0.0.1")
     self.CheckSocketCookie(AF_INET6, "::1")
@@ -410,7 +414,7 @@
       # Create a fully-specified diag req from our socket, including cookie if
       # we can get it.
       req = self.sock_diag.DiagReqFromSocket(s)
-      if HAVE_SO_COOKIE_SUPPORT:
+      if LINUX_4_9_OR_ABOVE:
         req.id.cookie = s.getsockopt(net_test.SOL_SOCKET, net_test.SO_COOKIE, 8)
       else:
         req.id.cookie = "\xff" * 16  # INET_DIAG_NOCOOKIE[2]
@@ -547,6 +551,50 @@
                        child.id.src)
 
 
+class TcpRcvWindowTest(tcp_test.TcpBaseTest, SockDiagBaseTest):
+
+  RWND_SIZE = 64000 if LINUX_4_19_OR_ABOVE else 42000
+  TCP_DEFAULT_INIT_RWND = "/proc/sys/net/ipv4/tcp_default_init_rwnd"
+
+  def setUp(self):
+    super(TcpRcvWindowTest, self).setUp()
+    if LINUX_4_19_OR_ABOVE:
+      self.assertRaisesErrno(ENOENT, open, self.TCP_DEFAULT_INIT_RWND, "w")
+      return
+
+    f = open(self.TCP_DEFAULT_INIT_RWND, "w")
+    f.write("60")
+
+  def checkInitRwndSize(self, version, netid):
+    self.IncomingConnection(version, tcp_test.TCP_ESTABLISHED, netid)
+    tcpInfo = TcpInfo(self.accepted.getsockopt(net_test.SOL_TCP,
+                                               net_test.TCP_INFO, len(TcpInfo)))
+    self.assertLess(self.RWND_SIZE, tcpInfo.tcpi_rcv_ssthresh,
+                    "Tcp rwnd of netid=%d, version=%d is not enough. "
+                    "Expect: %d, actual: %d" % (netid, version, self.RWND_SIZE,
+                                                tcpInfo.tcpi_rcv_ssthresh))
+
+  def checkSynPacketWindowSize(self, version, netid):
+    s = self.BuildSocket(version, net_test.TCPSocket, netid, "mark")
+    myaddr = self.MyAddress(version, netid)
+    dstaddr = self.GetRemoteAddress(version)
+    dstsockaddr = self.GetRemoteSocketAddress(version)
+    desc, expected = packets.SYN(53, version, myaddr, dstaddr,
+                                 sport=None, seq=None)
+    self.assertRaisesErrno(EINPROGRESS, s.connect, (dstsockaddr, 53))
+    msg = "IPv%s TCP connect: expected %s on %s" % (
+        version, desc, self.GetInterfaceName(netid))
+    syn = self.ExpectPacketOn(netid, msg, expected)
+    self.assertLess(self.RWND_SIZE, syn.window)
+    s.close()
+
+  def testTcpCwndSize(self):
+    for version in [4, 5, 6]:
+      for netid in self.NETIDS:
+        self.checkInitRwndSize(version, netid)
+        self.checkSynPacketWindowSize(version, netid)
+
+
 class SockDestroyTcpTest(tcp_test.TcpBaseTest, SockDiagBaseTest):
 
   def setUp(self):