net: fix potential deadlock

When sblock() fails we left "so" locked, which would cause that the
current thread will hold the lock forever. Spotted during code
inspection.

Signed-off-by: Tomasz Grabiec <tgrabiec@cloudius-systems.com>
Signed-off-by: Avi Kivity <avi@cloudius-systems.com>
net: extract common code

Signed-off-by: Tomasz Grabiec <tgrabiec@cloudius-systems.com>
Signed-off-by: Avi Kivity <avi@cloudius-systems.com>
net: drain net channel queue before socket is closed

Fixes #259.

Commit 8340e21b58b12af72d886fdfd58d307340d19e47 introduced an
assertion which verifies that tcpcb and socket are not freed during
tcp_net_channel_flush(). This is justified because
tcp_net_channel_flush() is called from places which assume these will
remain live. Bug #259 revealed a situation in which this does not
hold. It is possible that after socket is closed and moved to
FIN_WAIT_1 state there are still some packets in its net
channel. Later on when these packets will be flushed, tcp_do_segment()
will try to reset the connection according to the protocol. This must
not happen during tcp_net_channel_flush() and we hit an asseriton
failure.

To solve the problem, we must ensure that tcp_do_segment() will not
try to close TCP when it's called on packets from a net channel. Let's
walk over all possible places (which I was able to find):

 * Inside if (thflags & TH_RST) ...

   This should not happen because net channel classifier does not let
   in packets with RST, FIN or SYN flags.

 * Inside if ((so->so_state & SS_NOFDREF) &&
         tp->t_state > TCPS_CLOSE_WAIT && tlen)

   This is the one we hit in issue #259. In order to avoid it we must
   ensure that all packets from the net channel are drained after the
   classifier is unregistered but before the socket is marked as
   SS_NOFDREF (closed). This is fixed by this patch.

 * t_state == TCPS_LAST_ACK && ourfinisacked

   state is moved to TCPS_LAST_ACK when socket is closed while in
   TCPS_CLOSE_WAIT state. That state move happens after net channel
   classifier is unregstered in reaction to received FIN. After that
   we send our own FIN. Because the other side will send the final ACK
   after that, that final ACK cannot land in the net channel, so we
   should be good.

 * Entering TIME_WAIT state via tcp_twstart()

   tcp_twstart() frees the socket. This is not catched by "want_close"
   flag, but is as much prohibited. To enter TIME_WAIT we must first
   enter FIN_WAIT_1 and then receive ACK from the other side for our
   FIN (among other things). Because the classifier is unregistered
   before entering FIN_WAIT_1, the final ACK cannot go through the net
   channel. Therefore, tcp_net_channel_flush() cannot trigger
   TIME_WAIT state and we should be good.

Signed-off-by: Tomasz Grabiec <tgrabiec@cloudius-systems.com>
Signed-off-by: Avi Kivity <avi@cloudius-systems.com>
Merge branch '259'

Signed-off-by: Avi Kivity <avi@cloudius-systems.com>