home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD2.bin
/
bbs
/
comm
/
amitcp-3.0ß2.lha
/
AmiTCP
/
src
/
amitcp
/
netinet
/
tcp_output.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-12
|
17KB
|
578 lines
RCS_ID_C="$Id: tcp_output.c,v 1.9 1993/06/04 11:16:15 jraja Exp $";
/*
* Copyright (c) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
* Helsinki University of Technology, Finland.
* All rights reserved.
*
* HISTORY
* $Log: tcp_output.c,v $
* Revision 1.9 1993/06/04 11:16:15 jraja
* Fixes for first public release.
*
* Revision 1.8 1993/05/17 00:16:44 ppessi
* Changed RCS version. Added rcsid.
*
* Revision 1.7 1993/04/24 23:22:13 jraja
* Removed #ifdef NOALIGN, now using straight structure copies.
*
* Revision 1.6 93/04/13 22:16:32 22:16:32 jraja (Jarno Tapio Rajahalme)
* Added ALIGNED to the tcp_initopt (which was odd aligned).
*
* Revision 1.5 93/04/05 19:06:32 19:06:32 jraja (Jarno Tapio Rajahalme)
* Changed storage of the spl functions return values to type spl_t.
* Added include for conf.h to every .c file.
*
* Revision 1.4 93/03/22 16:59:39 16:59:39 jraja (Jarno Tapio Rajahalme)
* Changed bcopy()s and bzero()s with word aligned pointers to
* aligned_b(copy|zero) ar aligned_b(copy|zero)_const. The latter is for calls
* in which the size is constant.
* These can be disabled by defining NOALIGN.
* Converted bcopys doing structure copies (on aligned pointers) to structure
* assignments, since at least SASC produces better code with assignment.
*
* Revision 1.3 93/03/03 21:29:37 21:29:37 jraja (Jarno Tapio Rajahalme)
* Moved various data definitions from header files to here.
*
* Revision 1.2 93/02/26 09:49:02 09:49:02 jraja (Jarno Tapio Rajahalme)
* Made this compile with ANSI C (added prototypes).
* Added one (phony) argument to tcp_quench() call, since it now takes two
* arguments, but does not use the second.
*
* Revision 1.1 92/11/17 16:30:39 16:30:39 jraja (Jarno Tapio Rajahalme)
* Initial revision
*
*/
/*
* Copyright (c) 1982, 1986, 1988, 1990 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)tcp_output.c 7.22 (Berkeley) 8/31/90
*/
#include <conf.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/errno.h>
#include <sys/synch.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
#include <netinet/tcpip.h>
#include <netinet/tcp_debug.h>
#include <netinet/tcp_output_protos.h>
#include <netinet/tcp_input_protos.h>
#include <netinet/tcp_debug_protos.h>
#include <netinet/tcp_subr_protos.h>
#include <netinet/ip_output_protos.h>
#include <netinet/in_cksum_protos.h>
#ifdef notyet
extern struct mbuf *m_copypack();
#endif
/* --- start moved from tcp_fsm.h --- */
#ifdef TCPOUTFLAGS
/*
* Flags used when sending segments in tcp_output.
* Basic flags (TH_RST,TH_ACK,TH_SYN,TH_FIN) are totally
* determined by state, with the proviso that TH_FIN is sent only
* if all data queued for output is included in the segment.
*/
u_char tcp_outflags[TCP_NSTATES] = {
TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK,
TH_ACK, TH_ACK,
TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, TH_ACK, TH_ACK,
};
#endif
/* --- end moved from tcp_fsm.h --- */
/*
* Initial options.
*/
ALIGNED u_char tcp_initopt[4] = { TCPOPT_MAXSEG, 4, 0x0, 0x0, };
/*
* Tcp output routine: figure out what should be sent and send it.
*/
int
tcp_output(tp)
register struct tcpcb *tp;
{
register struct socket *so = tp->t_inpcb->inp_socket;
register long len, win;
int off, flags, error;
register struct mbuf *m;
register struct tcpiphdr *ti;
u_char *opt;
unsigned optlen, hdrlen;
int idle, sendalot;
/*
* Determine length of data that should be transmitted,
* and flags that will be used.
* If there is some data or critical controls (SYN, RST)
* to send, then transmit; otherwise, investigate further.
*/
idle = (tp->snd_max == tp->snd_una);
if (idle && tp->t_idle >= tp->t_rxtcur)
/*
* We have been idle for "a while" and no acks are
* expected to clock out any data we send --
* slow start to get ack "clock" running again.
*/
tp->snd_cwnd = tp->t_maxseg;
again:
sendalot = 0;
off = tp->snd_nxt - tp->snd_una;
win = min(tp->snd_wnd, tp->snd_cwnd);
/*
* If in persist timeout with window of 0, send 1 byte.
* Otherwise, if window is small but nonzero
* and timer expired, we will send what we can
* and go to transmit state.
*/
if (tp->t_force) {
if (win == 0)
win = 1;
else {
tp->t_timer[TCPT_PERSIST] = 0;
tp->t_rxtshift = 0;
}
}
flags = tcp_outflags[tp->t_state];
len = min(so->so_snd.sb_cc, win) - off;
if (len < 0) {
/*
* If FIN has been sent but not acked,
* but we haven't been called to retransmit,
* len will be -1. Otherwise, window shrank
* after we sent into it. If window shrank to 0,
* cancel pending retransmit and pull snd_nxt
* back to (closed) window. We will enter persist
* state below. If the window didn't close completely,
* just wait for an ACK.
*/
len = 0;
if (win == 0) {
tp->t_timer[TCPT_REXMT] = 0;
tp->snd_nxt = tp->snd_una;
}
}
if (len > tp->t_maxseg) {
len = tp->t_maxseg;
sendalot = 1;
}
if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
flags &= ~TH_FIN;
win = sbspace(&so->so_rcv);
/*
* Sender silly window avoidance. If connection is idle
* and can send all data, a maximum segment,
* at least a maximum default-size segment do it,
* or are forced, do it; otherwise don't bother.
* If peer's buffer is tiny, then send
* when window is at least half open.
* If retransmitting (possibly after persist timer forced us
* to send into a small window), then must resend.
*/
if (len) {
if (len == tp->t_maxseg)
goto send;
if ((idle || tp->t_flags & TF_NODELAY) &&
len + off >= so->so_snd.sb_cc)
goto send;
if (tp->t_force)
goto send;
if (len >= tp->max_sndwnd / 2)
goto send;
if (SEQ_LT(tp->snd_nxt, tp->snd_max))
goto send;
}
/*
* Compare available window to amount of window
* known to peer (as advertised window less
* next expected input). If the difference is at least two
* max size segments, or at least 50% of the maximum possible
* window, then want t