xref: /csrg-svn/sys/netinet/tcp_output.c (revision 5075)
1 /*	tcp_output.c	4.18	81/11/25	*/
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../net/inet.h"
9 #include "../net/inet_pcb.h"
10 #include "../net/inet_systm.h"
11 #include "../net/imp.h"
12 #include "../net/ip.h"
13 #include "../net/ip_var.h"
14 #include "../net/tcp.h"
15 #include "../net/tcp_var.h"
16 #include "../net/tcp_fsm.h"
17 #include "/usr/include/errno.h"
18 
19 /*
20  * Tcp output routine: figure out what should be sent
21  * and, if nothing, send a null segment anyways if force is nonzero
22  * (e.g. to be sure to send an ACK).
23  *
24  * This routine can be called only after SYNs have been exchanged.
25  */
26 tcp_output(tp)
27 	register struct tcpcb *tp;
28 {
29 	register struct socket *so = tp->t_inpcb->inp_socket;
30 	register int len;
31 	struct mbuf *m0;
32 	int off, flags;
33 	register struct mbuf *m;
34 	register struct tcpiphdr *ti;
35 	int win;
36 
37 COUNT(TCP_OUTPUT);
38 
39 	/*
40 	 * Determine length of data that can be transmitted.
41 	 * If will transmit to end of data and no more data
42 	 * is coming, then send FIN also.
43 	 * Make a copy of the data (if any).  If no data
44 	 * and not forced to transmit, just return.
45 	 */
46 	off = tp->snd_nxt - tp->snd_una;
47 	len = MIN(so->so_snd.sb_cc, tp->snd_wnd) - off;
48 	if (len > tp->mtu)
49 		len = tp->mtu;
50 	if (len == so->so_snd.sb_cc && (so->so_state & SS_CANTSNDMORE))
51 		flags = TH_FIN;
52 	else
53 		flags = 0;
54 	if (len)
55 		goto send;
56 
57 	/*
58 	 * No data to send: see if something else makes us want to send.
59 	 * First check if we owe peer and ack or have a unacked FIN to send.
60 	 */
61 	if (tp->t_flags & TF_OWEACK)
62 		goto send;
63 	if ((so->so_state & SS_CANTSNDMORE) &&
64 	    TCPS_OURFINISACKED(tp->t_state) == 0)
65 		goto send;
66 	if (tp->t_state == TCPS_SYN_SENT) {
67 		flags = TH_SYN;
68 		goto send;
69 	}
70 	if (tp->t_state == TCPS_CLOSED) {
71 		flags = TH_RST;
72 		goto send;
73 	}
74 
75 	/*
76 	 * Calculate available window in i, and also amount
77 	 * of window known to peer (as advertised window less
78 	 * next expected input.)  If this is 35% or more of the
79 	 * maximum possible window, then want to send a segment to peer.
80 	 */
81 	i = sbspace(&so->so_rcv) - tp->seqcnt;
82 	if (i > 0 &&
83 	    ((100*(i-(tp->rcv_adv-tp->rcv_nxt))/so->so_rcv.sb_hiwat) >= 35))
84 		goto send;
85 
86 	/*
87 	 * No reason to send a segment, just return.
88 	 */
89 	return;
90 
91 send:
92 	/*
93 	 * Grab a header mbuf, attaching a copy of data to
94 	 * be transmitted, and initialize the header from
95 	 * the template for sends on this connection.
96 	 */
97 	MGET(m, 0);
98 	if (m == 0)
99 		return (0);
100 	m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
101 	m->m_len = sizeof (struct tcpiphdr);
102 	if (len) {
103 		m->m_next = m_copy(so->so_snd.sb_mb, off, len);
104 		if (m->m_next == 0)
105 			len = 0;
106 	}
107 	ti = mtod(m, struct tcpiphdr *);
108 	if (tp->t_template == 0)
109 		panic("tcp_output");
110 	bcopy((caddr_t)tp->t_template, ti, sizeof (struct tcpiphdr));
111 
112 	/*
113 	 * Fill in fields, remembering maximum advertised
114 	 * window for use in delaying messages about window sizes.
115 	 */
116 	ti->ti_seq = htonl(tp->snd_nxt);
117 	ti->ti_ackno = htonl(tp->rcv_nxt);
118 	/* OPTIONS */
119 	if (flags & TH_SYN)
120 		ti->ti_flags = flags;
121 	else
122 		ti->ti_flags = flags | TH_ACK;
123 	win = sbspace(&so->so_rcv);
124 	if (win > 0)
125 		ti->ti_win = htons(win);
126 	if (SEQ_GT(tp->snd_urp, tp->snd_nxt))
127 		ti->ti_urp = htons((u_short)(tp->snd_urp - tp->snd_nxt));
128 		ti->ti_flags |= TH_URG;
129 	} else
130 		/*
131 		 * If no urgent pointer to send, then we pull
132 		 * the urgent pointer to the left edge of the send window
133 		 * so that it doesn't drift into the send window on sequence
134 		 * number wraparound.
135 		 */
136 		tp->snd_urp = tp->snd_una;		/* drag it along */
137 
138 	/*
139 	 * Put TCP length in extended header, and then
140 	 * checksum extended header and data.
141 	 */
142 	if (len)
143 		ti->ti_len = htons((u_short)(len + sizeof (struct tcphdr)));
144 	ti->ti_sum = inet_cksum(m, sizeof (struct tcpiphdr) + len);
145 
146 	/*
147 	 * Fill in IP length and desired time to live and
148 	 * send to IP level.
149 	 */
150 	((struct ip *)ti)->ip_len = len + sizeof (struct tcpiphdr);
151 	((struct ip *)ti)->ip_ttl = TCP_TTL;
152 	if (ip_output(m) == 0)
153 		return;
154 
155 	/*
156 	 * Data sent (as far as we can tell).
157 	 * If this advertises a larger window than any other segment,
158 	 * then record its sequence to be used in suppressing messages.
159 	 * Advance snd_nxt to reflect transmitted sequence space,
160 	 * drop send for purpose of ACK requirements,
161 	 * and time transmission if not a retransmit.
162 	 */
163 	if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))
164 		tp->rcv_adv = tp->rcv_nxt + win;
165 	tp->snd_nxt += len;
166 	tp->t_flags &= ~(TF_OWEACK|TF_DELACK);
167 	if (flags & TH_FIN)
168 		tp->snd_nxt++;
169 	if (SEQ_GT(tp->snd_nxt, tp->snd_hi)) {
170 		tp->snd_hi = tp->snd_nxt;
171 		/* TIME TRANSMIT */
172 	}
173 	return;
174 }
175