diff --git a/kernel/trunk/network/socket.inc b/kernel/trunk/network/socket.inc
index f997dc58b3..790edc3228 100644
--- a/kernel/trunk/network/socket.inc
+++ b/kernel/trunk/network/socket.inc
@@ -750,12 +750,15 @@ socket_close:
         ret
 
   .tcp:
-        call    tcp_usrclosed
-
-        test    eax, eax
+        test    [eax + SOCKET.state], SS_ISCONNECTED
         jz      @f
-        call    tcp_output                                      ; If connection is not closed yet, send the FIN
+        test    [eax + SOCKET.state], SS_ISDISCONNECTING
+        jnz     @f
+        call    tcp_disconnect
   @@:
+; TODO:
+; ...
+;       call    socket_free
         ret
 
 
@@ -2471,7 +2474,7 @@ socket_is_disconnecting:
 align 4
 socket_is_disconnected:
 
-        DEBUGF  DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnected: %x\n", eax
+        DEBUGF  1, "SOCKET_is_disconnected: %x\n", eax
 
         and     [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
         or      [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE
diff --git a/kernel/trunk/network/tcp_output.inc b/kernel/trunk/network/tcp_output.inc
index dbd3c579a9..fa0e5dfce2 100644
--- a/kernel/trunk/network/tcp_output.inc
+++ b/kernel/trunk/network/tcp_output.inc
@@ -32,7 +32,7 @@ proc tcp_output
 
 locals
         temp_bits       db ?
-        window          dd ?
+        rcv_window      dd ?
 endl
 
         DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: socket=%x state=%u\n", eax, [eax + TCP_SOCKET.t_state]
@@ -128,7 +128,7 @@ endl
 ; If FIN has been sent, but not ACKed, but we havent been called to retransmit, esi will be -1
 ; Otherwise, window shrank after we sent into it.
 
-        jae     .not_persist
+        jge     .not_persist
 
 ; enter persist state
 
@@ -176,8 +176,12 @@ endl
 ;-------------------------------
 ; calculate window advertisement
 
+        xor     ecx, ecx
+        test    [eax + SOCKET.state], SS_CANTRCVMORE
+        jnz     @f
         mov     ecx, SOCKET_BUFFER_SIZE
         sub     ecx, [eax + STREAM_SOCKET.rcv.size]
+  @@:
 
 ;------------------------------
 ; Sender silly window avoidance
@@ -235,7 +239,7 @@ endl
         add     ebx, [eax + TCP_SOCKET.RCV_NXT]
 
         cmp     ebx, ecx
-        jb      @f
+        jl      @f
         mov     ebx, ecx
        @@:
 
@@ -246,9 +250,8 @@ endl
         cmp     ebx, edi
         jae     .send
 
-        shl     ebx, 1
-;        cmp     ebx, [eax + TCP_SOCKET.]    ;;; TODO: check with receive buffer high water mark
-;        jae     TCP_send
+        cmp     ebx, SOCKET_BUFFER_SIZE/2
+        jae     .send
 
   .no_window:
 
@@ -289,11 +292,8 @@ endl
   .enter_persist:
 
         cmp     [eax + STREAM_SOCKET.snd.size], 0                       ; Data ready to send?
-        jne     @f
-        and     [eax + TCP_SOCKET.timer_flags], not timer_flag_retransmission
-        jne     @f
-
-        test    [eax + TCP_SOCKET.timer_flags], timer_flag_persist      ; Persist timer already expired?
+        je      @f
+        test    [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission or timer_flag_persist
         jnz     @f
 
         DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_output: Entering persist state\n"
@@ -485,20 +485,30 @@ endl
 ; Calculate the receive window.
 ; Dont shrink window, but avoid silly window syndrome
 
+        xor     ebx, ebx
+        test    [eax + SOCKET.state], SS_CANTRCVMORE
+        jnz     @f
         mov     ebx, SOCKET_BUFFER_SIZE
         sub     ebx, [eax + STREAM_SOCKET.rcv.size]
 
         cmp     ebx, SOCKET_BUFFER_SIZE/4
-        jae     @f
+        jge     @f
         cmp     ebx, [eax + TCP_SOCKET.t_maxseg]
-        jae     @f
+        jge     @f
         xor     ebx, ebx
   @@:
 
-        cmp     ebx, TCP_max_win ;;;; shl rcv_scale
-        jbe     @f
-        mov     ebx, TCP_max_win ;;;; shl rcv_scale
+
+        mov     cl, [eax + TCP_SOCKET.RCV_SCALE]
+        push    eax
+        mov     eax, TCP_max_win
+        shl     eax, cl
+        cmp     ebx, eax
+        jle     @f
+        mov     ebx, eax
   @@:
+        pop     eax
+
 
         mov     ecx, [eax + TCP_SOCKET.RCV_ADV]
         sub     ecx, [eax + TCP_SOCKET.RCV_NXT]
@@ -507,8 +517,10 @@ endl
         mov     ebx, ecx
   @@:
 
+;; TODO URGENT POINTER
+
         DEBUGF  DEBUG_NETWORK_VERBOSE, "TCP_send: window=%u\n", ebx
-        mov     [window], ebx
+        mov     [rcv_window], ebx
 
         mov     cl, [eax + TCP_SOCKET.RCV_SCALE]
         shr     ebx, cl
@@ -668,7 +680,7 @@ endl
 
 ; update advertised receive window
 
-        mov     ecx, [window]
+        mov     ecx, [rcv_window]
         test    ecx, ecx
         jz      @f
         add     ecx, [eax + TCP_SOCKET.RCV_NXT]
diff --git a/kernel/trunk/network/tcp_subr.inc b/kernel/trunk/network/tcp_subr.inc
index 9268cd22d5..a35a1e0d17 100644
--- a/kernel/trunk/network/tcp_subr.inc
+++ b/kernel/trunk/network/tcp_subr.inc
@@ -185,9 +185,22 @@ tcp_disconnect:
         cmp     [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
         jb      tcp_close       ; Connection not yet synchronised, just get rid of the socket
 
-; TODO: implement LINGER
+        test    [eax + SOCKET.options], SO_LINGER
+        jz      .nolinger
 
+; TODO: implement LINGER
+;        cmp     [eax + SOCKET.so_linger], 0
+;        je     TCP_drop
+
+  .nolinger:
         call    socket_is_disconnecting
+
+        push    eax
+        add     eax, STREAM_SOCKET.rcv
+        mov     ecx, [eax + RING_BUFFER.size]
+        call    socket_ring_free
+        pop     eax
+
         call    tcp_usrclosed
 
         test    eax, eax
@@ -311,7 +324,7 @@ tcp_respond:
         cmp     eax, TCP_max_win
         jbe     .lessthanmax
         mov     eax, TCP_max_win
-.lessthanmax:
+  .lessthanmax:
         mov     cl, [esi + TCP_SOCKET.RCV_SCALE]
         shr     eax, cl