xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4677)
1*4677Swnj /* tcp_output.c 4.1 81/10/30 */
2*4677Swnj 
3*4677Swnj #include "../h/param.h"
4*4677Swnj #include "../h/systm.h"
5*4677Swnj #include "../h/mbuf.h"
6*4677Swnj #include "../h/socket.h"
7*4677Swnj #include "../inet/inet.h"
8*4677Swnj #include "../inet/inet_host.h"
9*4677Swnj #include "../inet/inet_systm.h"
10*4677Swnj #include "../inet/imp.h"
11*4677Swnj #include "../inet/ip.h"
12*4677Swnj #include "../inet/tcp.h"
13*4677Swnj #include "../inet/tcp_fsm.h"
14*4677Swnj 
15*4677Swnj send(tp)                        /* send data */
16*4677Swnj 	register struct tcb *tp;
17*4677Swnj {
18*4677Swnj 	register struct ucb *up;
19*4677Swnj 	register unsigned long last, wind;
20*4677Swnj 	struct mbuf *m;
21*4677Swnj 	int flags = 0, forced, sent;
22*4677Swnj 	struct mbuf *tcp_sndcopy();
23*4677Swnj 	int len;
24*4677Swnj 
25*4677Swnj COUNT(SEND);
26*4677Swnj 	up = tp->t_ucb;
27*4677Swnj 	tp->snd_lst = tp->snd_nxt;
28*4677Swnj 	forced = 0;
29*4677Swnj 	m = NULL;
30*4677Swnj 
31*4677Swnj 	if (tp->snd_nxt == tp->iss) {           /* first data to be sent */
32*4677Swnj 		flags |= TH_SYN;
33*4677Swnj 		tp->snd_lst++;
34*4677Swnj 	}
35*4677Swnj 
36*4677Swnj 	/* get seq # of last datum in send buffer */
37*4677Swnj 
38*4677Swnj 	last = tp->snd_off;
39*4677Swnj 	for (m = up->uc_sbuf; m != NULL; m = m->m_next)
40*4677Swnj 		last += m->m_len;
41*4677Swnj 
42*4677Swnj         /* no data to send in buffer */
43*4677Swnj 
44*4677Swnj 	if (tp->snd_nxt > last) {
45*4677Swnj 
46*4677Swnj 		/* should we send FIN?  don't unless haven't already sent one */
47*4677Swnj 
48*4677Swnj 		if ((tp->tc_flags&TC_SND_FIN) &&
49*4677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
50*4677Swnj 
51*4677Swnj 			flags |= TH_FIN;
52*4677Swnj 			tp->seq_fin = tp->snd_lst++;
53*4677Swnj 		}
54*4677Swnj 
55*4677Swnj 	} else {                                  /* there is data to send */
56*4677Swnj 
57*4677Swnj 		/* send data only if there is a window defined */
58*4677Swnj 
59*4677Swnj 		if (tp->tc_flags&TC_SYN_ACKED) {
60*4677Swnj 
61*4677Swnj 			wind = tp->snd_una + tp->snd_wnd;
62*4677Swnj 
63*4677Swnj 			/* use window to limit send */
64*4677Swnj 
65*4677Swnj 			tp->snd_lst = min(last, wind);
66*4677Swnj 
67*4677Swnj 			/* make sure we don't do ip fragmentation */
68*4677Swnj 
69*4677Swnj 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
70*4677Swnj 				tp->snd_lst -= len - 1024;
71*4677Swnj 
72*4677Swnj 			/* set persist timer */
73*4677Swnj 
74*4677Swnj 			if (tp->snd_lst >= wind)
75*4677Swnj 				tp->t_persist = T_PERS;
76*4677Swnj 		}
77*4677Swnj 
78*4677Swnj 		/* check if window is closed and must force a byte out */
79*4677Swnj 
80*4677Swnj 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
81*4677Swnj 			tp->snd_lst = tp->snd_nxt + 1;
82*4677Swnj 			forced = 1;
83*4677Swnj 		}
84*4677Swnj 
85*4677Swnj 		/* copy data to send from send buffer */
86*4677Swnj 
87*4677Swnj 		m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst);
88*4677Swnj 
89*4677Swnj 		/* see if EOL should be sent */
90*4677Swnj 
91*4677Swnj 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
92*4677Swnj 			flags |= TH_EOL;
93*4677Swnj 
94*4677Swnj 		/* must send FIN and no more data left to send after this */
95*4677Swnj 
96*4677Swnj 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
97*4677Swnj 		    tp->snd_lst == last &&
98*4677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
99*4677Swnj 
100*4677Swnj 			flags |= TH_FIN;
101*4677Swnj 			tp->seq_fin = tp->snd_lst++;
102*4677Swnj 		}
103*4677Swnj 	}
104*4677Swnj 
105*4677Swnj 	if (tp->snd_nxt < tp->snd_lst) {        /* something to send */
106*4677Swnj 
107*4677Swnj 		if (tp->tc_flags & TC_SND_URG)
108*4677Swnj 			flags |= TH_URG;
109*4677Swnj 		sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
110*4677Swnj 		/* set timers for retransmission if necessary */
111*4677Swnj 
112*4677Swnj 		if (!forced) {
113*4677Swnj 			tp->t_rexmt = tp->t_xmtime;
114*4677Swnj 			tp->t_rexmt_val = tp->snd_lst;
115*4677Swnj 
116*4677Swnj 			if ((tp->tc_flags&TC_REXMT) == 0) {
117*4677Swnj 				tp->t_rexmttl = T_REXMTTL;
118*4677Swnj 				tp->t_rtl_val = tp->snd_lst;
119*4677Swnj 			}
120*4677Swnj 
121*4677Swnj 		}
122*4677Swnj 
123*4677Swnj 		/* update seq for next send if this one got out */
124*4677Swnj 
125*4677Swnj 		if (sent)
126*4677Swnj 			tp->snd_nxt = tp->snd_lst;
127*4677Swnj 
128*4677Swnj 
129*4677Swnj 		/* if last timed message has been acked, start timing
130*4677Swnj 		   this one */
131*4677Swnj 
132*4677Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) && tp->snd_una > tp->t_xmt_val) {
133*4677Swnj 			tp->t_xmt = 0;
134*4677Swnj 			tp->t_xmt_val = tp->snd_lst;
135*4677Swnj 		}
136*4677Swnj 
137*4677Swnj 		tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
138*4677Swnj 		tp->snd_hi = max(tp->snd_nxt, tp->snd_hi);
139*4677Swnj 		return (1);
140*4677Swnj 	}
141*4677Swnj 
142*4677Swnj 	return(0);
143*4677Swnj }
144*4677Swnj 
145*4677Swnj tcp_sndctl(tp)                            /* send a control msg */
146*4677Swnj 	struct tcb *tp;
147*4677Swnj {
148*4677Swnj COUNT(SEND_CTL);
149*4677Swnj         if (!send(tp)) {
150*4677Swnj 		tcp_sndnull(tp);
151*4677Swnj 		return(0);
152*4677Swnj 	}
153*4677Swnj 	return(1);
154*4677Swnj }
155*4677Swnj 
156*4677Swnj int	printhave = 0;
157*4677Swnj 
158*4677Swnj tcp_sndwin(tp)
159*4677Swnj 	struct tcb *tp;
160*4677Swnj {
161*4677Swnj 	int ihave;
162*4677Swnj 	int hehas;
163*4677Swnj 
164*4677Swnj 	if (tp->rcv_adv) {
165*4677Swnj 		/* figure out window we would advertise */
166*4677Swnj 		ihave = tp->t_ucb->uc_rhiwat -
167*4677Swnj 		    (tp->t_ucb->uc_rcc + tp->seqcnt);
168*4677Swnj 		hehas = tp->rcv_adv - tp->rcv_nxt;
169*4677Swnj 		if (printhave)
170*4677Swnj 		printf("ihave %d, hehas %d\n", ihave, hehas);
171*4677Swnj 		if (hehas > 32 &&
172*4677Swnj 		   (100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35)
173*4677Swnj 			return;
174*4677Swnj 		if (printhave)
175*4677Swnj 		printf("update him\n");
176*4677Swnj 	}
177*4677Swnj         if (send(tp))
178*4677Swnj 		return (1);
179*4677Swnj 	tcp_sndnull(tp);
180*4677Swnj 	return (0);
181*4677Swnj }
182*4677Swnj tcp_sndnull(tp)				/* send only control information */
183*4677Swnj 	register struct tcb *tp;
184*4677Swnj {
185*4677Swnj COUNT(SEND_NULL);
186*4677Swnj 
187*4677Swnj 	tcp_output(tp, 0, 0, (struct mbuf *)0);
188*4677Swnj         tp->tc_flags &= ~TC_ACK_DUE;
189*4677Swnj }
190*4677Swnj 
191*4677Swnj tcp_sndrst(tp, n)                         /* send a reset */
192*4677Swnj 	register struct tcb *tp;
193*4677Swnj 	register struct th *n;
194*4677Swnj {
195*4677Swnj COUNT(SEND_RST);
196*4677Swnj         /* don't send a reset in response to a reset */
197*4677Swnj 
198*4677Swnj 	if (n->th_flags&TH_RST)
199*4677Swnj 		return;
200*4677Swnj 
201*4677Swnj 	tp->tc_flags |= TC_SND_RST;
202*4677Swnj 
203*4677Swnj 	if (n->th_flags&TH_ACK)
204*4677Swnj 		tp->snd_nxt = n->t_ackno;
205*4677Swnj 
206*4677Swnj 	tp->tc_flags &= ~TC_SYN_RCVD;
207*4677Swnj 	tcp_sndnull(tp);
208*4677Swnj 	tp->tc_flags &= ~TC_SND_RST;
209*4677Swnj }
210*4677Swnj 
211*4677Swnj /*
212*4677Swnj  * Create template to be used to send tcp packets on a connection.
213*4677Swnj  * Call after host entry created, allocates an mbuf and fills
214*4677Swnj  * in a skeletal tcp/ip header, minimizing the amount of work
215*4677Swnj  * necessary when the connection is used.
216*4677Swnj  */
217*4677Swnj struct th *
218*4677Swnj tcp_template(tp)
219*4677Swnj 	struct tcb *tp;
220*4677Swnj {
221*4677Swnj 	register struct host *h = tp->t_ucb->uc_host;
222*4677Swnj 	register struct mbuf *m;
223*4677Swnj 	register struct th *n;
224*4677Swnj 	register struct ip *ip;
225*4677Swnj 
226*4677Swnj 	if (h == 0)
227*4677Swnj 		return (0);
228*4677Swnj 	m = m_get(1);
229*4677Swnj 	if (m == 0)
230*4677Swnj 		return (0);
231*4677Swnj 	m->m_off = MMAXOFF - sizeof (struct th);
232*4677Swnj 	m->m_len = sizeof (struct th);
233*4677Swnj 	n = mtod(m, struct th *);
234*4677Swnj 	n->t_next = n->t_prev = 0;
235*4677Swnj 	n->t_x1 = 0;
236*4677Swnj 	n->t_pr = TCPROTO;
237*4677Swnj 	n->t_len = htons(sizeof (struct th) - sizeof (struct ip));
238*4677Swnj 	n->t_s.s_addr = n_lhost.s_addr;
239*4677Swnj 	n->t_d.s_addr = h->h_addr.s_addr;
240*4677Swnj 	n->t_src = htons(tp->t_lport);
241*4677Swnj 	n->t_dst = htons(tp->t_fport);
242*4677Swnj 	n->t_seq = 0;
243*4677Swnj 	n->t_ackno = 0;
244*4677Swnj 	n->t_x2 = 0;
245*4677Swnj 	n->t_off = 5;
246*4677Swnj 	n->th_flags = 0;
247*4677Swnj 	n->t_win = 0;
248*4677Swnj 	n->t_sum = 0;
249*4677Swnj 	n->t_urp = 0;
250*4677Swnj 	return (n);
251*4677Swnj }
252*4677Swnj 
253*4677Swnj tcp_output(tp, flags, len, dat)
254*4677Swnj 	register struct tcb *tp;
255*4677Swnj 	register int flags;
256*4677Swnj 	int len;
257*4677Swnj 	struct mbuf *dat;
258*4677Swnj {
259*4677Swnj 	register struct mbuf *m;
260*4677Swnj 	register struct th *t;
261*4677Swnj 	register struct ip *ip;
262*4677Swnj 	int i;
263*4677Swnj #ifdef TCPDEBUG
264*4677Swnj 	struct tcp_debug tdb;
265*4677Swnj #endif
266*4677Swnj COUNT(SEND_TCP);
267*4677Swnj 
268*4677Swnj 	if ((t = tp->t_ucb->uc_template) == 0)
269*4677Swnj 		return (0);
270*4677Swnj 	MGET(m, 0);
271*4677Swnj 	if (m == 0)
272*4677Swnj 		return (0);
273*4677Swnj 	m->m_off = MMAXOFF - sizeof(struct th);
274*4677Swnj 	m->m_len = sizeof (struct th);
275*4677Swnj 	m->m_next = dat;
276*4677Swnj 	if (flags & TH_SYN)
277*4677Swnj 		len--;
278*4677Swnj 	if (flags & TH_FIN)
279*4677Swnj 		len--;
280*4677Swnj 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th));
281*4677Swnj 	t = mtod(m, struct th *);
282*4677Swnj 	if (tp->tc_flags&TC_SND_RST) {
283*4677Swnj 		flags &= ~TH_SYN;
284*4677Swnj 		flags |= TH_RST;
285*4677Swnj 	}
286*4677Swnj 	if (tp->tc_flags&TC_SYN_RCVD)
287*4677Swnj 		flags |= TH_ACK;
288*4677Swnj 	t->th_flags = flags;
289*4677Swnj 	if (flags & TH_URG)
290*4677Swnj 		t->t_urp = htons(tp->snd_urp);
291*4677Swnj 	t->t_win =
292*4677Swnj 	    tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt);
293*4677Swnj 	if (tp->rcv_nxt + t->t_win > tp->rcv_adv)
294*4677Swnj 		tp->rcv_adv = tp->rcv_nxt + t->t_win;
295*4677Swnj 	if (len)
296*4677Swnj 		t->t_len = htons(len + TCPSIZE);
297*4677Swnj 	t->t_win = htons(t->t_win);
298*4677Swnj #ifdef TCPDEBUG
299*4677Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
300*4677Swnj 		t->t_seq = tp->snd_nxt;
301*4677Swnj 		t->t_ackno = tp->rcv_nxt;
302*4677Swnj 		tdb_setup(tp, t, INSEND, &tdb);
303*4677Swnj 		tdb_stuff(&tdb, -2);
304*4677Swnj 	}
305*4677Swnj #endif
306*4677Swnj 	t->t_seq = htonl(tp->snd_nxt);
307*4677Swnj 	t->t_ackno = htonl(tp->rcv_nxt);
308*4677Swnj 	t->t_sum = cksum(m, len + sizeof(struct th));
309*4677Swnj 	ip = (struct ip *)t;
310*4677Swnj 	ip->ip_v = IPVERSION;
311*4677Swnj 	ip->ip_hl = 5;
312*4677Swnj 	ip->ip_tos = 0;
313*4677Swnj 	ip->ip_len = len + sizeof(struct th);
314*4677Swnj 	ip->ip_id = ip_id++;
315*4677Swnj 	ip->ip_off = 0;
316*4677Swnj 	ip->ip_ttl = MAXTTL;
317*4677Swnj 	i = ip_send(ip);
318*4677Swnj #ifdef notdef
319*4677Swnj 	if (tp->t_ucb->uc_flags & UDEBUG) {
320*4677Swnj 		w.w_dat = (char *)t;
321*4677Swnj 		w.w_stype = i;
322*4677Swnj 		tcp_debug(tp, &w, INRECV, -1);
323*4677Swnj 	}
324*4677Swnj #endif
325*4677Swnj 	return(i);
326*4677Swnj }
327*4677Swnj 
328*4677Swnj firstempty(tp)
329*4677Swnj 	register struct tcb *tp;
330*4677Swnj {
331*4677Swnj 	register struct th *p, *q;
332*4677Swnj COUNT(FIRSTEMPTY);
333*4677Swnj 
334*4677Swnj 	if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq)
335*4677Swnj 		return (tp->rcv_nxt);
336*4677Swnj 	while ((q = p->t_next) != (struct th *)tp &&
337*4677Swnj 	    (t_end(p) + 1) == q->t_seq)
338*4677Swnj 		p = q;
339*4677Swnj 	return (t_end(p) + 1);
340*4677Swnj }
341*4677Swnj 
342*4677Swnj /* SHOULD BE A MACRO, AFTER KEEP TRACK OF ASS Q SPACE */
343*4677Swnj 
344*4677Swnj struct mbuf *
345*4677Swnj tcp_sndcopy(tp, start, end)
346*4677Swnj 	struct tcb *tp;
347*4677Swnj 	u_long start, end;
348*4677Swnj {
349*4677Swnj 	register struct mbuf *m, *n, **np;
350*4677Swnj 	u_long off;
351*4677Swnj 	register int len;
352*4677Swnj 	int adj;
353*4677Swnj 	struct mbuf *top, *p;
354*4677Swnj COUNT(SND_COPY);
355*4677Swnj 
356*4677Swnj /*
357*4677Swnj 	printf("st %x end %x off %x\n", start, end, tp->snd_off);
358*4677Swnj */
359*4677Swnj 	if (start >= end)
360*4677Swnj 		return(NULL);
361*4677Swnj 	off = tp->snd_off;
362*4677Swnj 	m = tp->t_ucb->uc_sbuf;
363*4677Swnj 	while (m != NULL && start >= (off + m->m_len)) {
364*4677Swnj 		off += m->m_len;
365*4677Swnj 		m = m->m_next;
366*4677Swnj 	}
367*4677Swnj 	np = &top;
368*4677Swnj 	top = 0;
369*4677Swnj 	adj = start - off;
370*4677Swnj 	len = end - start;
371*4677Swnj 	while (m && len > 0) {
372*4677Swnj 		MGET(n, 1);
373*4677Swnj 		*np = n;
374*4677Swnj 		if (n == 0)
375*4677Swnj 			goto nospace;
376*4677Swnj 		n->m_len = MIN(len, m->m_len - adj);
377*4677Swnj 		if (m->m_off > MMAXOFF) {
378*4677Swnj 			p = mtod(m, struct mbuf *);
379*4677Swnj 			n->m_off = ((int)p - (int)n) + adj;
380*4677Swnj 			mprefcnt[mtopf(p)]++;
381*4677Swnj 		} else {
382*4677Swnj 			n->m_off = MMINOFF;
383*4677Swnj 			bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t),
384*4677Swnj 			    n->m_len);
385*4677Swnj 		}
386*4677Swnj 		len -= n->m_len;
387*4677Swnj 		adj = 0;
388*4677Swnj 		m = m->m_next;
389*4677Swnj 		/* SHOULD TRY PACKING INTO SMALL MBUFS HERE */
390*4677Swnj 		np = &n->m_next;
391*4677Swnj 	}
392*4677Swnj 	/* SHOULD NEVER RUN OUT OF m WHEN LEN */
393*4677Swnj 	if (len)
394*4677Swnj 		printf("snd_copy: m %x len %d\n", m, len);
395*4677Swnj 	return (top);
396*4677Swnj nospace:
397*4677Swnj 	printf("snd_copy: no space\n");
398*4677Swnj 	m_freem(top);
399*4677Swnj 	return (0);
400*4677Swnj }
401*4677Swnj 
402*4677Swnj tcp_enq(p, prev)
403*4677Swnj 	register struct th *p;
404*4677Swnj 	register struct th *prev;
405*4677Swnj {
406*4677Swnj 
407*4677Swnj 	p->t_prev = prev;
408*4677Swnj 	p->t_next = prev->t_next;
409*4677Swnj 	prev->t_next->t_prev = p;
410*4677Swnj 	prev->t_next = p;
411*4677Swnj }
412*4677Swnj 
413*4677Swnj tcp_deq(p)
414*4677Swnj 	register struct th *p;
415*4677Swnj {
416*4677Swnj 
417*4677Swnj 	p->t_prev->t_next = p->t_next;
418*4677Swnj 	p->t_next->t_prev = p->t_prev;
419*4677Swnj }
420