xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4567)
1*4567Swnj /* tcp_usrreq.c 1.4 81/10/21 */
2*4567Swnj 
34497Swnj #include "../h/param.h"
4*4567Swnj #include "../h/systm.h"
54497Swnj #include "../bbnnet/net.h"
64497Swnj #include "../bbnnet/tcp.h"
74497Swnj #include "../bbnnet/ip.h"
84497Swnj #include "../bbnnet/imp.h"
94497Swnj #include "../bbnnet/ucb.h"
10*4567Swnj #define TCPFSTAB
114497Swnj #include "../bbnnet/fsm.h"
124497Swnj #include "../bbnnet/tcp_pred.h"
134497Swnj 
14*4567Swnj /*
15*4567Swnj  * This file contains the top level routines for actions
16*4567Swnj  * called by the user and by the clock routines, while input
17*4567Swnj  * actions for network data are driven by tcp_input.  The two
18*4567Swnj  * main entry points here are tcp_timeo, which decrements tcp timers
19*4567Swnj  * each second and runs timer action routines when the timers go off,
20*4567Swnj  * and tcp_usrreq, which performs requests generated by or on behalf
21*4567Swnj  * of user processes.  Both routines raise the ipl to splnet to block
22*4567Swnj  * off tcp_input processing (triggered by imp's) during the work
23*4567Swnj  * here.
24*4567Swnj  */
25*4567Swnj 
26*4567Swnj tcp_timeo()
274497Swnj {
28*4567Swnj 	register struct tcb *tp;
29*4567Swnj 	int s = splnet();
30*4567Swnj COUNT(TCP_TIMEO);
314497Swnj 
32*4567Swnj 	/*
33*4567Swnj 	 * Search through tcb's and update active timers.
34*4567Swnj 	 */
35*4567Swnj 	for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) {
36*4567Swnj 		if (tp->t_init != 0 && --tp->t_init == 0)
37*4567Swnj 			tcp_usrreq(ISTIMER, TINIT, tp, 0);
38*4567Swnj 		if (tp->t_rexmt != 0 && --tp->t_rexmt == 0)
39*4567Swnj 			tcp_usrreq(ISTIMER, TREXMT, tp, 0);
40*4567Swnj 		if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0)
41*4567Swnj 			tcp_usrreq(ISTIMER, TREXMTTL, tp, 0);
42*4567Swnj 		if (tp->t_persist != 0 && --tp->t_persist == 0)
43*4567Swnj 			tcp_usrreq(ISTIMER, TPERSIST, tp, 0);
44*4567Swnj 		if (tp->t_finack != 0 && --tp->t_finack == 0)
45*4567Swnj 			tcp_usrreq(ISTIMER, TFINACK, tp, 0);
46*4567Swnj 		tp->t_xmt++;
47*4567Swnj 	}
48*4567Swnj 	netcb.n_iss += ISSINCR;		/* increment iss */
49*4567Swnj 	timeout(tcp_timeo, 0, hz);      /* reschedule every second */
50*4567Swnj 	splx(s);
514497Swnj }
524497Swnj 
53*4567Swnj tcp_usrreq(input, stype, tp, m)
54*4567Swnj 	int input, stype;
55*4567Swnj 	register struct tcb *tp;
56*4567Swnj 	char *m;
574497Swnj {
58*4567Swnj 	struct work w;
59*4567Swnj 	int s = splnet();
60*4567Swnj 	register int nstate;
61*4567Swnj 	register struct work *wp = &w;
62*4567Swnj COUNT(TCP_USRREQ);
634497Swnj 
64*4567Swnj 	wp->w_type = input;
65*4567Swnj 	wp->w_stype = stype;
66*4567Swnj 	wp->w_tcb = tp;
67*4567Swnj 	wp->w_dat = m;
68*4567Swnj 	nstate = tp->t_state;
69*4567Swnj 	tp->net_keep = 0;
70*4567Swnj 	acounts[nstate][input]++;
71*4567Swnj 	switch (tcp_fstab[nstate][input]) {
724497Swnj 
73*4567Swnj 	default:
74*4567Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
75*4567Swnj 		    tp, tp->t_state, input);
76*4567Swnj 		nstate = EFAILEC;
77*4567Swnj 		break;
784497Swnj 
79*4567Swnj 	case LIS_CLS:				/* 1 */
80*4567Swnj 		t_open(tp, PASSIVE);
81*4567Swnj 		nstate = LISTEN;
82*4567Swnj 		break;
834497Swnj 
84*4567Swnj 	case SYS_CLS:				/* 2 */
85*4567Swnj 		t_open(tp, ACTIVE);
86*4567Swnj 		send_ctl(tp);
87*4567Swnj 		nstate = SYN_SENT;
88*4567Swnj 		break;
894497Swnj 
90*4567Swnj 	case CLS_OPN:				/* 10 */
91*4567Swnj 		t_close(tp, UCLOSED);
92*4567Swnj 		nstate = CLOSED;
93*4567Swnj 		break;
944497Swnj 
95*4567Swnj 	case CL2_CLW:				/* 10 */
96*4567Swnj 		tp->snd_fin = 1;
97*4567Swnj 		send_ctl(tp);
98*4567Swnj 		tp->usr_closed = 1;
99*4567Swnj 		nstate = CLOSING2;
100*4567Swnj 		break;
1014497Swnj 
102*4567Swnj 	case TIMERS:				/* 14,17,34,35,36,37,38 */
103*4567Swnj 		nstate = tcp_timers(wp);
104*4567Swnj 		break;
1054497Swnj 
106*4567Swnj 	case CLS_RWT:				/* 20 */
107*4567Swnj 		present_data(tp);
108*4567Swnj 		if (rcv_empty(tp)) {
109*4567Swnj 			t_close(tp, UCLOSED);
110*4567Swnj 			nstate = CLOSED;
111*4567Swnj 		} else
112*4567Swnj 			nstate = RCV_WAIT;
113*4567Swnj 		break;
1144497Swnj 
115*4567Swnj 	case FW1_SYR:				/* 24,25 */
116*4567Swnj 		tp->snd_fin = 1;
117*4567Swnj 		send_ctl(tp);
118*4567Swnj 		tp->usr_closed = 1;
119*4567Swnj 		nstate = FIN_W1;
120*4567Swnj 		break;
121*4567Swnj 
122*4567Swnj 	case SSS_SND:				/* 40,41 */
123*4567Swnj 		nstate = sss_snd(wp);
124*4567Swnj 		break;
125*4567Swnj 
126*4567Swnj 	case SSS_RCV:				/* 42 */
127*4567Swnj 		send_ctl(tp);		/* send new window */
128*4567Swnj 		present_data(tp);
129*4567Swnj 		break;
130*4567Swnj 
131*4567Swnj 	case CLS_NSY:				/* 44 */
132*4567Swnj 		t_close(tp, UABORT);
133*4567Swnj 		nstate = CLOSED;
134*4567Swnj 		break;
135*4567Swnj 
136*4567Swnj 	case CLS_SYN:				/* 45 */
137*4567Swnj 		tp->snd_rst = 1;
138*4567Swnj 		send_null(tp);
139*4567Swnj 		t_close(tp, UABORT);
140*4567Swnj 		nstate = CLOSED;
141*4567Swnj 		break;
142*4567Swnj 
143*4567Swnj 	case CLS_ACT:				/* 47 */
144*4567Swnj 		t_close(tp, UNETDWN);
145*4567Swnj 		nstate = CLOSED;
146*4567Swnj 		break;
147*4567Swnj 
148*4567Swnj 	case NOP:
149*4567Swnj 		break;
150*4567Swnj 
151*4567Swnj 	case CLS_ERR:
152*4567Swnj 		to_user(tp->t_ucb, UCLSERR);
153*4567Swnj 		break;
154*4567Swnj 	}
155*4567Swnj 	if (tp->t_ucb->uc_flags & UDEBUG)
156*4567Swnj 		tcp_debug(tp, wp, input, nstate);
157*4567Swnj #ifdef TCPDEBUG
158*4567Swnj 	tcp_prt(tp, input, wp->w_stype, nstate);
159*4567Swnj #endif
160*4567Swnj 	/* YECH */
161*4567Swnj 	switch (nstate) {
162*4567Swnj 
163*4567Swnj 	case SAME:
164*4567Swnj 		break;
165*4567Swnj 
166*4567Swnj 	case EFAILEC:
167*4567Swnj 		if (m)
168*4567Swnj 			m_freem(dtom(m));
169*4567Swnj 		break;
170*4567Swnj 
171*4567Swnj 	default:
172*4567Swnj 		tp->t_state = nstate;
173*4567Swnj 		break;
174*4567Swnj 	}
175*4567Swnj 	splx(s);
1764497Swnj }
1774497Swnj 
178*4567Swnj t_open(tp, mode)                /* set up a tcb for a connection */
179*4567Swnj 	register struct tcb *tp;
180*4567Swnj 	int mode;
1814497Swnj {
182*4567Swnj 	register struct ucb *up;
183*4567Swnj COUNT(T_OPEN);
1844497Swnj 
185*4567Swnj 	/* enqueue the tcb */
1864497Swnj 
187*4567Swnj 	if (netcb.n_tcb_head == NULL) {
188*4567Swnj 		netcb.n_tcb_head = tp;
189*4567Swnj 		netcb.n_tcb_tail = tp;
190*4567Swnj 	} else {
191*4567Swnj 		tp->t_tcb_next = netcb.n_tcb_head;
192*4567Swnj 		netcb.n_tcb_head->t_tcb_prev = tp;
193*4567Swnj 		netcb.n_tcb_head = tp;
194*4567Swnj 	}
1954497Swnj 
196*4567Swnj 	/* initialize non-zero tcb fields */
1974497Swnj 
198*4567Swnj 	tp->t_rcv_next = (struct th *)tp;
199*4567Swnj 	tp->t_rcv_prev = (struct th *)tp;
200*4567Swnj 	tp->t_xmtime = T_REXMT;
201*4567Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi =
202*4567Swnj 	              tp->snd_una = tp->iss = netcb.n_iss;
203*4567Swnj 	tp->snd_off = tp->iss + 1;
204*4567Swnj 	netcb.n_iss += (ISSINCR >> 1) + 1;
205*4567Swnj 
206*4567Swnj 	/* set timeout for open */
207*4567Swnj 
208*4567Swnj 	up = tp->t_ucb;
209*4567Swnj 	tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo :
210*4567Swnj 					(mode == ACTIVE ? T_INIT : 0));
211*4567Swnj 	up->uc_timeo = 0;       /* overlays uc_ssize */
2124497Swnj }
2134497Swnj 
214*4567Swnj t_close(tp, state)
215*4567Swnj 	register struct tcb *tp;
216*4567Swnj 	short state;
2174497Swnj {
218*4567Swnj 	register struct ucb *up;
219*4567Swnj 	register struct th *t;
220*4567Swnj 	register struct mbuf *m;
221*4567Swnj 	register struct work *w;
222*4567Swnj COUNT(T_CLOSE);
2234497Swnj 
224*4567Swnj 	up = tp->t_ucb;
2254497Swnj 
226*4567Swnj 	tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist =
227*4567Swnj 	    tp->t_finack = 0;
2284497Swnj 
229*4567Swnj 	/* delete tcb */
230*4567Swnj 
231*4567Swnj 	if (tp->t_tcb_prev == NULL)
232*4567Swnj 		netcb.n_tcb_head = tp->t_tcb_next;
233*4567Swnj 	else
234*4567Swnj 		tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next;
235*4567Swnj 	if (tp->t_tcb_next == NULL)
236*4567Swnj 		netcb.n_tcb_tail = tp->t_tcb_prev;
237*4567Swnj 	else
238*4567Swnj 		tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev;
239*4567Swnj 
240*4567Swnj 	/* free all data on receive and send buffers */
241*4567Swnj 
242*4567Swnj 	for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next)
243*4567Swnj 		m_freem(dtom(t));
244*4567Swnj 
245*4567Swnj 	if (up->uc_rbuf != NULL) {
246*4567Swnj 		m_freem(up->uc_rbuf);
247*4567Swnj 		up->uc_rbuf = NULL;
248*4567Swnj 	}
249*4567Swnj 	if (up->uc_sbuf != NULL) {
250*4567Swnj 		m_freem(up->uc_sbuf);
251*4567Swnj 		up->uc_sbuf = NULL;
252*4567Swnj 	}
253*4567Swnj 	for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) {
254*4567Swnj 		m_freem(m);
255*4567Swnj 		tp->t_rcv_unack = NULL;
256*4567Swnj 	}
257*4567Swnj 	m_free(dtom(tp));
258*4567Swnj 	up->uc_tcb = NULL;
259*4567Swnj 
260*4567Swnj 	/* lower buffer allocation and decrement host entry */
261*4567Swnj 
262*4567Swnj 	netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2;
263*4567Swnj 	netcb.n_hiwat = 2 * netcb.n_lowat;
264*4567Swnj 	if (up->uc_host != NULL) {
265*4567Swnj 		h_free(up->uc_host);
266*4567Swnj 		up->uc_host = NULL;
267*4567Swnj 	}
268*4567Swnj 
269*4567Swnj 	/* if user has initiated close (via close call), delete ucb
270*4567Swnj 	   entry, otherwise just wakeup so user can issue close call */
271*4567Swnj 
272*4567Swnj 	if (tp->usr_abort)
273*4567Swnj         	up->uc_proc = NULL;
274*4567Swnj 	else
275*4567Swnj         	to_user(up, state);
276*4567Swnj 
2774497Swnj }
2784497Swnj 
279*4567Swnj sss_snd(wp)
280*4567Swnj 	struct work *wp;
2814497Swnj {
2824497Swnj 	register struct tcb *tp;
2834497Swnj 	register struct mbuf *m, *n;
2844497Swnj 	register struct ucb *up;
2854497Swnj 	register off;
2864497Swnj 	sequence last;
2874497Swnj 
2884497Swnj 	tp = wp->w_tcb;
2894497Swnj 	up = tp->t_ucb;
2904497Swnj 
2914497Swnj 	last = tp->snd_off;
2924497Swnj 
2934497Swnj 	/* count number of mbufs in send data */
2944497Swnj 
2954497Swnj 	for (m = n = (struct mbuf *)wp->w_dat; m != NULL; m = m->m_next) {
2964497Swnj 		up->uc_ssize++;
2974497Swnj 		last += m->m_len;
2984497Swnj 	}
2994497Swnj 
3004497Swnj 	/* find end of send buffer and append data */
3014497Swnj 
302*4567Swnj 	if ((m = up->uc_sbuf) != NULL) {		/* something in send buffer */
303*4567Swnj 		while (m->m_next != NULL) {		/* find the end */
3044497Swnj 			m = m->m_next;
3054497Swnj 			last += m->m_len;
3064497Swnj 		}
3074497Swnj 		last += m->m_len;
3084497Swnj 
3094497Swnj 		/* if there's room in old buffer for new data, consolidate */
3104497Swnj 
3114497Swnj 		off = m->m_off + m->m_len;
3124497Swnj 		while (n != NULL && (MSIZE - off) >= n->m_len) {
313*4567Swnj 			bcopy((caddr_t)((int)n + n->m_off),
3144497Swnj 			      (caddr_t)((int)m + off), n->m_len);
3154497Swnj 			m->m_len += n->m_len;
3164497Swnj 			off += n->m_len;
3174497Swnj 			up->uc_ssize--;
3184497Swnj 			n = m_free(n);
3194497Swnj 		}
3204497Swnj 		m->m_next = n;
3214497Swnj 
322*4567Swnj 	} else		/* nothing in send buffer */
3234497Swnj 		up->uc_sbuf = n;
3244497Swnj 
325*4567Swnj 	if (up->uc_flags & UEOL) {		/* set EOL */
3264497Swnj 		tp->snd_end = last;
3274497Swnj 	}
3284497Swnj 
329*4567Swnj 	if (up->uc_flags & UURG) {		/* urgent data */
3304497Swnj 		tp->snd_urp = last+1;
331*4567Swnj 		tp->snd_urg = 1;
332*4567Swnj 	}
3334497Swnj 
3344497Swnj 	send(tp);
3354497Swnj 
336*4567Swnj 	return (SAME);
3374497Swnj }
3384497Swnj 
339*4567Swnj tcp_timers(wp)
340*4567Swnj 	struct work *wp;
3414497Swnj {
342*4567Swnj 	register struct tcb *tp = wp->w_tcb;
343*4567Swnj 	register type = wp->w_stype;
3444497Swnj 
345*4567Swnj COUNT(TCP_TIMERS);
346*4567Swnj 	switch (type) {
3474497Swnj 
348*4567Swnj 	case TINIT:		/* initialization timer */
349*4567Swnj 		if (!tp->syn_acked) {				/* 35 */
350*4567Swnj 			t_close(tp, UINTIMO);
351*4567Swnj 			return (CLOSED);
352*4567Swnj 		}
353*4567Swnj 		return (SAME);
3544497Swnj 
355*4567Swnj 	case TFINACK:		/* fin-ack timer */
356*4567Swnj 		switch (tp->t_state) {
3574497Swnj 
358*4567Swnj 		case TIME_WAIT:
359*4567Swnj 			/*
360*4567Swnj 			 * We can be sure our ACK of foreign FIN was rcvd,
361*4567Swnj 			 * and can close if no data left for user.
362*4567Swnj 			 */
363*4567Swnj 			if (rcv_empty(tp)) {
364*4567Swnj 				t_close(tp, UCLOSED);		/* 14 */
365*4567Swnj 				return (CLOSED);
366*4567Swnj 			}
367*4567Swnj 			return (RCV_WAIT);			/* 17 */
3684497Swnj 
369*4567Swnj 		case CLOSING1:
370*4567Swnj 			tp->waited_2_ml = 1;
371*4567Swnj 			return (SAME);
3724497Swnj 
373*4567Swnj 		default:
374*4567Swnj 			return (SAME);
375*4567Swnj 		}
3764497Swnj 
377*4567Swnj 	case TREXMT:		/* retransmission timer */
378*4567Swnj 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
379*4567Swnj 			/*
380*4567Swnj 			 * Set up for a retransmission, increase rexmt time
381*4567Swnj 			 * in case of multiple retransmissions.
382*4567Swnj 			 */
383*4567Swnj 			tp->snd_nxt = tp->snd_una;
384*4567Swnj 			tp->rexmt = 1;
385*4567Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
386*4567Swnj 			if (tp->t_xmtime > T_REMAX)
387*4567Swnj 				tp->t_xmtime = T_REMAX;
388*4567Swnj 			send(tp);
389*4567Swnj 		}
390*4567Swnj 		return (SAME);
3914497Swnj 
392*4567Swnj 	case TREXMTTL:		/* retransmit too long */
393*4567Swnj 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
394*4567Swnj 			to_user(tp->t_ucb, URXTIMO);
395*4567Swnj 		/*
396*4567Swnj 		 * If user has already closed, abort the connection.
397*4567Swnj 		 */
398*4567Swnj 		if (tp->usr_closed) {
399*4567Swnj 			t_close(tp, URXTIMO);
400*4567Swnj 			return (CLOSED);
401*4567Swnj 		}
402*4567Swnj 		return (SAME);
4034497Swnj 
404*4567Swnj 	case TPERSIST:		/* persist timer */
405*4567Swnj 		/*
406*4567Swnj 		 * Force a byte send through closed window.
407*4567Swnj 		 */
408*4567Swnj 		tp->force_one = 1;				/* 38 */
409*4567Swnj 		send(tp);
410*4567Swnj 		return (SAME);
411*4567Swnj 	}
412*4567Swnj 	panic("tcp_timers");
4134497Swnj }
4144497Swnj 
415*4567Swnj tcp_debug(tp, wp, input, newstate)   /* write a debugging record */
416*4567Swnj 	register struct tcb *tp;
417*4567Swnj 	register struct work *wp;
418*4567Swnj 	int input, newstate;
4194497Swnj {
420*4567Swnj 	struct t_debug debuf;
421*4567Swnj 	register struct th *n;
422*4567Swnj 	register off_t siz;
423*4567Swnj COUNT(TCP_DEBUG);
4244497Swnj 
425*4567Swnj 	/* look for debugging file inode */
4264497Swnj 
427*4567Swnj 	if (netcb.n_debug == 0)
428*4567Swnj 		return;
429*4567Swnj 	debuf.t_tod = time;
430*4567Swnj 	if ((debuf.t_tcb = tp) != NULL)
431*4567Swnj 		debuf.t_old = tp->t_state;
432*4567Swnj 	else
433*4567Swnj 		debuf.t_old = 0;
434*4567Swnj 	debuf.t_inp = input;
435*4567Swnj 	debuf.t_tim = wp->w_stype;
436*4567Swnj 	debuf.t_new = newstate;
437*4567Swnj 	if (input == INRECV) {
438*4567Swnj 		n = (struct th *)wp->w_dat;
439*4567Swnj 		debuf.t_sno = n->t_seq;
440*4567Swnj 		debuf.t_ano = n->t_ackno;
441*4567Swnj 		debuf.t_wno = n->t_win;
442*4567Swnj 		if (debuf.t_new == -1)
443*4567Swnj 			debuf.t_lno = ((struct ip *)n)->ip_len;
444*4567Swnj 		else
445*4567Swnj 			debuf.t_lno = n->t_len;
446*4567Swnj 		debuf.t_flg = *(char *)((int)&n->t_win - 1);
447*4567Swnj 	}
448*4567Swnj 	/* STUFF INTO CIRC BUFFER */
4494497Swnj }
4504497Swnj 
451*4567Swnj #ifdef TCPDEBUG
452*4567Swnj 
453*4567Swnj tcp_prt(tp, input, timer, newstate)     /* print debugging info on the console */
454*4567Swnj register struct tcb *tp;
455*4567Swnj register input, timer, newstate;
4564497Swnj {
457*4567Swnj 	register oldstate;
458*4567Swnj COUNT(TCP_PRT);
4594497Swnj 
460*4567Swnj 	oldstate = tp->t_state;
461*4567Swnj 	printf("TCP(%X) %s X %s", tp, tcpstates[oldstate], tcpinputs[input]);
462*4567Swnj 	if (input == ISTIMER)
463*4567Swnj 		printf("(%s)", tcptimers[timer]);
464*4567Swnj 	printf(" --> %s", tcpstates[ (newstate > 0) ? newstate : oldstate ]);
465*4567Swnj 	if (newstate < 0)
466*4567Swnj 		printf(" (FAILED)\n");
467*4567Swnj 	else
468*4567Swnj 		putchar('\n');
4694497Swnj }
470*4567Swnj #endif
4714497Swnj 
472*4567Swnj /* THIS ROUTINE IS A CROCK */
473*4567Swnj to_user(up, state)
474*4567Swnj 	register struct ucb *up;
475*4567Swnj 	register short state;
4764497Swnj {
477*4567Swnj COUNT(TO_USER);
4784497Swnj 
479*4567Swnj 	up->uc_state |= state;
480*4567Swnj 	netwakeup(up);
481*4567Swnj   	if (state == UURGENT)
482*4567Swnj 		psignal(up->uc_proc, SIGURG);
4834497Swnj }
484