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