xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4900)
1 /* tcp_output.c 4.12 81/11/15 */
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_cksum.h"
9 #include "../net/inet.h"
10 #include "../net/inet_host.h"
11 #include "../net/inet_pcb.h"
12 #include "../net/inet_systm.h"
13 #include "../net/imp.h"
14 #include "../net/ip.h"
15 #include "../net/ip_var.h"
16 #include "../net/tcp.h"
17 #include "../net/tcp_var.h"
18 #include "../net/tcp_fsm.h"
19 #include "/usr/include/errno.h"
20 
21 /*
22  * Special routines to send control messages.
23  */
24 tcp_sndctl(tp)
25 	struct tcpcb *tp;
26 {
27 COUNT(TCP_SNDCTL);
28 
29         if (tcp_send(tp))
30 		return (1);
31 	tcp_sndnull(tp);
32 	return (0);
33 }
34 
35 tcp_sndwin(tp)
36 	struct tcpcb *tp;
37 {
38 	int ihave, hehas;
39 COUNT(TCP_SNDWIN);
40 
41 	if (tp->rcv_adv) {
42 		register struct socket *so = tp->t_inpcb->inp_socket;
43 
44 		ihave = so->so_rcv.sb_hiwat -
45 		    (so->so_rcv.sb_cc + tp->seqcnt);
46 		hehas = tp->rcv_adv - tp->rcv_nxt;
47 		if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
48 			return;
49 	}
50         if (tcp_send(tp))
51 		return (1);
52 	tcp_sndnull(tp);
53 	return (0);
54 }
55 
56 tcp_sndnull(tp)
57 	register struct tcpcb *tp;
58 {
59 COUNT(TCP_SNDNULL);
60 
61 	tcp_output(tp, 0, 0, (struct mbuf *)0);
62         tp->tc_flags &= ~TC_ACK_DUE;
63 }
64 
65 tcp_sndrst(tp, n)
66 	register struct tcpcb *tp;
67 	register struct tcpiphdr *n;
68 {
69 COUNT(TCP_SNDRST);
70 
71         /* don't send a reset in response to a reset */
72 	if (n->ti_flags&TH_RST)
73 		return;
74 	tp->tc_flags |= TC_SND_RST;
75 	if (n->ti_flags&TH_ACK)
76 		tp->snd_nxt = n->ti_ackno;
77 	tp->tc_flags &= ~TC_SYN_RCVD;
78 	tcp_sndnull(tp);
79 	tp->tc_flags &= ~TC_SND_RST;
80 }
81 
82 /*
83  * Tcp segment output routine.
84  */
85 tcp_send(tp)
86 	register struct tcpcb *tp;
87 {
88 	register unsigned long last, wind;
89 	register struct socket *so = tp->t_inpcb->inp_socket;
90 	struct mbuf *m;
91 	int flags = 0, forced, sent, len;
92 
93 COUNT(TCP_SEND);
94 	tp->snd_lst = tp->snd_nxt;
95 	forced = 0;
96 	m = NULL;
97 	if (tp->snd_nxt == tp->iss) {
98 		flags |= TH_SYN;
99 		tp->snd_lst++;
100 	}
101 	last = tp->snd_off;
102 	for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
103 		last += m->m_len;
104 	if (tp->snd_nxt > last) {
105 		if ((tp->tc_flags&TC_SND_FIN) &&
106 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
107 
108 			flags |= TH_FIN;
109 			tp->seq_fin = tp->snd_lst++;
110 		}
111 	} else {
112 		if (tp->tc_flags&TC_SYN_ACKED) {
113 			wind = tp->snd_una + tp->snd_wnd;
114 			tp->snd_lst = min(last, wind);
115 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
116 				tp->snd_lst -= len - 1024;
117 			if (tp->snd_lst >= wind)
118 				tp->t_persist = T_PERS;
119 		}
120 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
121 			tp->snd_lst = tp->snd_nxt + 1;
122 			forced = 1;
123 		} else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
124 			return (0);
125 		m = sb_copy(&so->so_snd,
126 		      MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off,
127 		      tp->snd_lst - tp->snd_off);
128 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
129 			flags |= TH_EOL;
130 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
131 		    tp->snd_lst == last &&
132 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
133 			flags |= TH_FIN;
134 			tp->seq_fin = tp->snd_lst++;
135 		}
136 	}
137 	if (tp->snd_nxt >= tp->snd_lst)
138 		return (0);
139 	if (tp->tc_flags & TC_SND_URG)
140 		flags |= TH_URG;
141 	sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
142 	if (!forced) {
143 		tp->t_rexmt = tp->t_xmtime;
144 		tp->t_rexmt_val = tp->snd_lst;
145 		if ((tp->tc_flags&TC_REXMT) == 0) {
146 			tp->t_rexmttl = T_REXMTTL;
147 			tp->t_rtl_val = tp->snd_lst;
148 		}
149 	}
150 	if (sent)
151 		tp->snd_nxt = tp->snd_lst;
152 	if ((tp->tc_flags&TC_SYN_ACKED) &&
153 	    tp->snd_una > tp->t_xmt_val) {
154 		tp->t_xmt = 0;
155 		tp->t_xmt_val = tp->snd_lst;
156 	}
157 	tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
158 	tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
159 	return (1);
160 }
161 
162 /*
163  * Create template to be used to send tcp packets on a connection.
164  * Call after host entry created, allocates an mbuf and fills
165  * in a skeletal tcp/ip header, minimizing the amount of work
166  * necessary when the connection is used.
167  */
168 struct tcpiphdr *
169 tcp_template(tp)
170 	struct tcpcb *tp;
171 {
172 	register struct inpcb *inp = tp->t_inpcb;
173 	register struct in_host *h = inp->inp_fhost;
174 	register struct mbuf *m;
175 	register struct tcpiphdr *n;
176 
177 	if (h == 0)
178 		return (0);
179 	m = m_get(1);
180 	if (m == 0)
181 		return (0);
182 	m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
183 	m->m_len = sizeof (struct tcpiphdr);
184 	n = mtod(m, struct tcpiphdr *);
185 	n->ti_next = n->ti_prev = 0;
186 	n->ti_x1 = 0;
187 	n->ti_pr = IPPROTO_TCP;
188 	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
189 	n->ti_src.s_addr = n_lhost.s_addr;
190 	n->ti_dst.s_addr = h->h_addr.s_addr;
191 	n->ti_sport = htons(inp->inp_lport);
192 	n->ti_dport = htons(inp->inp_fport);
193 	n->ti_seq = 0;
194 	n->ti_ackno = 0;
195 	n->ti_x2 = 0;
196 	n->ti_off = 5;
197 	n->ti_flags = 0;
198 	n->ti_win = 0;
199 	n->ti_sum = 0;
200 	n->ti_urp = 0;
201 	return (n);
202 }
203 
204 tcp_output(tp, flags, len, dat)
205 	register struct tcpcb *tp;
206 	register int flags;
207 	int len;
208 	struct mbuf *dat;
209 {
210 	register struct tcpiphdr *t;			/* known to be r9 */
211 	register struct mbuf *m;
212 	struct socket *so = tp->t_inpcb->inp_socket;
213 	register struct ip *ip;
214 	int i;
215 #ifdef TCPDEBUG
216 	struct tcp_debug tdb;
217 #endif
218 COUNT(TCP_OUTPUT);
219 
220 	if ((t = tp->t_template) == 0)
221 		return (0);
222 	MGET(m, 0);
223 	if (m == 0)
224 		return (0);
225 	m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
226 	m->m_len = sizeof (struct tcpiphdr);
227 	m->m_next = dat;
228 	if (flags & TH_SYN)
229 		len--;
230 	if (flags & TH_FIN)
231 		len--;
232 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
233 	t = mtod(m, struct tcpiphdr *);
234 	if (tp->tc_flags&TC_SND_RST) {
235 		flags &= ~TH_SYN;
236 		flags |= TH_RST;
237 	}
238 	if (tp->tc_flags&TC_SYN_RCVD)
239 		flags |= TH_ACK;
240 	t->ti_flags = flags;
241 	if (flags & TH_URG)
242 		t->ti_urp = htons(tp->snd_urp);
243 	t->ti_win =
244 	    so->so_rcv.sb_hiwat -
245 		(so->so_rcv.sb_cc + tp->seqcnt);
246 	if (tp->rcv_nxt + t->ti_win > tp->rcv_adv)
247 		tp->rcv_adv = tp->rcv_nxt + t->ti_win;
248 	if (len)
249 		t->ti_len = htons(len + TCPSIZE);
250 	t->ti_win = htons(t->ti_win);
251 #ifdef TCPDEBUG
252 	if ((so->so_options & SO_DEBUG) || tcpconsdebug) {
253 		t->ti_seq = tp->snd_nxt;
254 		t->ti_ackno = tp->rcv_nxt;
255 		tdb_setup(tp, t, INSEND, &tdb);
256 		tdb_stuff(&tdb, -2);
257 	}
258 #endif
259 	t->ti_seq = htonl(tp->snd_nxt);
260 	t->ti_ackno = htonl(tp->rcv_nxt);
261 	t->ti_sum = 0;		/* gratuitous? */
262 	CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len);
263 	ip = (struct ip *)t;
264 	ip->ip_v = IPVERSION;
265 	ip->ip_hl = 5;
266 	ip->ip_tos = 0;
267 	ip->ip_len = len + sizeof(struct tcpiphdr);
268 	ip->ip_id = ip_id++;
269 	ip->ip_off = 0;
270 	ip->ip_ttl = MAXTTL;
271 	i = ip_send(ip);
272 	return (i);
273 }
274 
275 tcp_fasttimo()
276 {
277 
278 }
279