Add TCP resets sent to stack.Stats.

Change-Id: I40d5b2cac3de9eaaa79d85d871d97b0c9f8089e2
diff --git a/tcpip/tcpip.go b/tcpip/tcpip.go
index e419999..cde2a55 100644
--- a/tcpip/tcpip.go
+++ b/tcpip/tcpip.go
@@ -428,13 +428,14 @@
 		// InvalidSegmentsReceived is the number of TCP segments received that
 		// the transport layer could not parse.
 		InvalidSegmentsReceived uint64
-
 		// SegmentsSent is the number of TCP segments sent from the transport
 		// layer. Excludes shutdown, reset, and syn segments, because those
 		// segments are sent via stack.Route, which writes directly to the network
 		// endpoint (bypassing the transport endpoint and its associated Stats
 		// struct completely).
 		SegmentsSent uint64
+		// ResetsSent is the number of TCP resets sent.
+		ResetsSent uint64
 	}
 }
 
diff --git a/tcpip/transport/tcp/connect.go b/tcpip/transport/tcp/connect.go
index b4d0d8e..9582576 100644
--- a/tcpip/transport/tcp/connect.go
+++ b/tcpip/transport/tcp/connect.go
@@ -489,6 +489,10 @@
 // sendRaw sends a TCP segment to the endpoint's peer.
 func (e *endpoint) sendRaw(data buffer.View, flags byte, seq, ack seqnum.Value, rcvWnd seqnum.Size) *tcpip.Error {
 	atomic.AddUint64(&e.stack.MutableStats().TCP.SegmentsSent, 1)
+
+	if (flags & flagRst) != 0 {
+		atomic.AddUint64(&e.stack.MutableStats().TCP.ResetsSent, 1)
+	}
 	if e.sendTSOk {
 		// Embed the timestamp if timestamp has been enabled.
 		//
diff --git a/tcpip/transport/tcp/tcp_test.go b/tcpip/transport/tcp/tcp_test.go
index 2ce3b49..95de8bc 100644
--- a/tcpip/transport/tcp/tcp_test.go
+++ b/tcpip/transport/tcp/tcp_test.go
@@ -158,6 +158,58 @@
 	}
 }
 
+func TestTCPResetsSentIncrement(t *testing.T) {
+	c := context.New(t, defaultMTU)
+	defer c.Cleanup()
+	stats := c.Stack().MutableStats()
+	wq := &waiter.Queue{}
+	ep, err := c.Stack().NewEndpoint(tcp.ProtocolNumber, ipv4.ProtocolNumber, wq)
+	if err != nil {
+		t.Fatalf("NewEndpoint failed: %v", err)
+	}
+	expected := stats.TCP.SegmentsSent + 1
+
+	if err := ep.Bind(tcpip.FullAddress{Port: context.StackPort}, nil); err != nil {
+		t.Fatalf("Bind failed: %v", err)
+	}
+
+	if err := ep.Listen(10); err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+
+	// Send a SYN request.
+	iss := seqnum.Value(789)
+	c.SendPacket(nil, &context.Headers{
+		SrcPort: context.TestPort,
+		DstPort: context.StackPort,
+		Flags:   header.TCPFlagSyn,
+		SeqNum:  iss,
+	})
+
+	// Receive the SYN-ACK reply.
+	b := c.GetPacket()
+	tcp := header.TCP(header.IPv4(b).Payload())
+	c.IRS = seqnum.Value(tcp.SequenceNumber())
+
+	ackHeaders := &context.Headers{
+		SrcPort: context.TestPort,
+		DstPort: context.StackPort,
+		Flags:   header.TCPFlagAck,
+		SeqNum:  iss + 1,
+		// If the AckNum is not the increment of the last sequence number, a RST
+		// segment is sent back in response.
+		AckNum: c.IRS + 2,
+	}
+
+	// Send ACK.
+	c.SendPacket(nil, ackHeaders)
+
+	c.GetPacket()
+	if actual := stats.TCP.ResetsSent; actual != expected {
+		t.Fatalf("Expected SegmentsSent to be %d, got %d", expected, actual)
+	}
+}
+
 func TestActiveHandshake(t *testing.T) {
 	c := context.New(t, defaultMTU)
 	defer c.Cleanup()