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