xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4592)
1*4592Swnj /* tcp_usrreq.c 1.10 81/10/23 */
24567Swnj 
34497Swnj #include "../h/param.h"
44567Swnj #include "../h/systm.h"
54497Swnj #include "../bbnnet/net.h"
64574Swnj #include "../bbnnet/mbuf.h"
74497Swnj #include "../bbnnet/tcp.h"
84497Swnj #include "../bbnnet/ip.h"
94497Swnj #include "../bbnnet/imp.h"
104497Swnj #include "../bbnnet/ucb.h"
114567Swnj #define TCPFSTAB
124584Swnj #ifdef TCPDEBUG
134584Swnj #define TCPSTATES
144584Swnj #endif
154497Swnj #include "../bbnnet/fsm.h"
164497Swnj 
174567Swnj tcp_timeo()
184497Swnj {
194567Swnj 	register struct tcb *tp;
204567Swnj 	int s = splnet();
214567Swnj COUNT(TCP_TIMEO);
224497Swnj 
234567Swnj 	/*
244567Swnj 	 * Search through tcb's and update active timers.
254567Swnj 	 */
264567Swnj 	for (tp = netcb.n_tcb_head; tp != NULL; tp = tp->t_tcb_next) {
274567Swnj 		if (tp->t_init != 0 && --tp->t_init == 0)
284567Swnj 			tcp_usrreq(ISTIMER, TINIT, tp, 0);
294567Swnj 		if (tp->t_rexmt != 0 && --tp->t_rexmt == 0)
304567Swnj 			tcp_usrreq(ISTIMER, TREXMT, tp, 0);
314567Swnj 		if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0)
324567Swnj 			tcp_usrreq(ISTIMER, TREXMTTL, tp, 0);
334567Swnj 		if (tp->t_persist != 0 && --tp->t_persist == 0)
344567Swnj 			tcp_usrreq(ISTIMER, TPERSIST, tp, 0);
354567Swnj 		if (tp->t_finack != 0 && --tp->t_finack == 0)
364567Swnj 			tcp_usrreq(ISTIMER, TFINACK, tp, 0);
374567Swnj 		tp->t_xmt++;
384567Swnj 	}
394567Swnj 	netcb.n_iss += ISSINCR;		/* increment iss */
404567Swnj 	timeout(tcp_timeo, 0, hz);      /* reschedule every second */
414567Swnj 	splx(s);
424497Swnj }
434497Swnj 
444584Swnj tcp_usrreq(input, timertype, tp, mp)
454584Swnj 	int input, timertype;
464567Swnj 	register struct tcb *tp;
474584Swnj 	struct mbuf *mp;
484497Swnj {
494567Swnj 	int s = splnet();
504567Swnj 	register int nstate;
514584Swnj #ifdef TCPDEBUG
524584Swnj 	struct tcp_debug tdb;
534584Swnj #endif
544567Swnj COUNT(TCP_USRREQ);
554497Swnj 
564567Swnj 	nstate = tp->t_state;
574576Swnj 	tp->tc_flags &= ~TC_NET_KEEP;
584567Swnj 	acounts[nstate][input]++;
594584Swnj #ifdef TCPDEBUG
604584Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
614584Swnj 		tdb.td_tod = time;
624584Swnj 		tdb.td_tcb = tp;
634584Swnj 		tdb.td_old = nstate;
644584Swnj 		tdb.td_inp = input;
654584Swnj 		tdb.td_tim = timertype;
664584Swnj 	} else
674584Swnj 		tdb.td_tod = 0;
684584Swnj #endif
694567Swnj 	switch (tcp_fstab[nstate][input]) {
704497Swnj 
714567Swnj 	default:
724567Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
734567Swnj 		    tp, tp->t_state, input);
744567Swnj 		nstate = EFAILEC;
754567Swnj 		break;
764497Swnj 
774567Swnj 	case LIS_CLS:				/* 1 */
784567Swnj 		t_open(tp, PASSIVE);
794567Swnj 		nstate = LISTEN;
804567Swnj 		break;
814497Swnj 
824567Swnj 	case SYS_CLS:				/* 2 */
834567Swnj 		t_open(tp, ACTIVE);
844567Swnj 		send_ctl(tp);
854567Swnj 		nstate = SYN_SENT;
864567Swnj 		break;
874497Swnj 
884567Swnj 	case CLS_OPN:				/* 10 */
894567Swnj 		t_close(tp, UCLOSED);
904567Swnj 		nstate = CLOSED;
914567Swnj 		break;
924497Swnj 
934567Swnj 	case CL2_CLW:				/* 10 */
944576Swnj 		tp->tc_flags |= TC_SND_FIN;
954567Swnj 		send_ctl(tp);
964576Swnj 		tp->tc_flags |= TC_USR_CLOSED;
974567Swnj 		nstate = CLOSING2;
984567Swnj 		break;
994497Swnj 
1004567Swnj 	case TIMERS:				/* 14,17,34,35,36,37,38 */
1014584Swnj 		nstate = tcp_timers(tp, timertype);
1024567Swnj 		break;
1034497Swnj 
1044567Swnj 	case CLS_RWT:				/* 20 */
1054567Swnj 		present_data(tp);
1064567Swnj 		if (rcv_empty(tp)) {
1074567Swnj 			t_close(tp, UCLOSED);
1084567Swnj 			nstate = CLOSED;
1094567Swnj 		} else
1104567Swnj 			nstate = RCV_WAIT;
1114567Swnj 		break;
1124497Swnj 
1134567Swnj 	case FW1_SYR:				/* 24,25 */
1144576Swnj 		tp->tc_flags |= TC_SND_FIN;
1154567Swnj 		send_ctl(tp);
1164576Swnj 		tp->tc_flags |= TC_USR_CLOSED;
1174567Swnj 		nstate = FIN_W1;
1184567Swnj 		break;
1194567Swnj 
1204567Swnj 	case SSS_SND:				/* 40,41 */
1214584Swnj 		nstate = sss_snd(tp, mp);
1224567Swnj 		break;
1234567Swnj 
1244567Swnj 	case SSS_RCV:				/* 42 */
1254567Swnj 		send_ctl(tp);		/* send new window */
1264567Swnj 		present_data(tp);
1274567Swnj 		break;
1284567Swnj 
1294567Swnj 	case CLS_NSY:				/* 44 */
1304567Swnj 		t_close(tp, UABORT);
1314567Swnj 		nstate = CLOSED;
1324567Swnj 		break;
1334567Swnj 
1344567Swnj 	case CLS_SYN:				/* 45 */
1354576Swnj 		tp->tc_flags |= TC_SND_RST;
1364567Swnj 		send_null(tp);
1374567Swnj 		t_close(tp, UABORT);
1384567Swnj 		nstate = CLOSED;
1394567Swnj 		break;
1404567Swnj 
1414567Swnj 	case CLS_ACT:				/* 47 */
1424567Swnj 		t_close(tp, UNETDWN);
1434567Swnj 		nstate = CLOSED;
1444567Swnj 		break;
1454567Swnj 
1464567Swnj 	case NOP:
1474567Swnj 		break;
1484567Swnj 
1494567Swnj 	case CLS_ERR:
1504567Swnj 		to_user(tp->t_ucb, UCLSERR);
1514567Swnj 		break;
1524567Swnj 	}
1534567Swnj #ifdef TCPDEBUG
1544584Swnj 	if (tdb.td_tod) {
1554584Swnj 		tdb.td_new = nstate;
1564584Swnj 		tcp_debug[tdbx++ % TDBSIZE] = tdb;
1574584Swnj 		if (tcpconsdebug)
1584584Swnj 			tcp_prt(&tdb);
1594584Swnj 	}
1604567Swnj #endif
1614567Swnj 	/* YECH */
1624567Swnj 	switch (nstate) {
1634567Swnj 
1644584Swnj 	case CLOSED:
1654567Swnj 	case SAME:
1664567Swnj 		break;
1674567Swnj 
1684567Swnj 	case EFAILEC:
1694584Swnj 		if (mp)
1704584Swnj 			m_freem(dtom(mp));
1714567Swnj 		break;
1724567Swnj 
1734567Swnj 	default:
1744567Swnj 		tp->t_state = nstate;
1754567Swnj 		break;
1764567Swnj 	}
1774567Swnj 	splx(s);
1784497Swnj }
1794497Swnj 
1804567Swnj t_open(tp, mode)                /* set up a tcb for a connection */
1814567Swnj 	register struct tcb *tp;
1824567Swnj 	int mode;
1834497Swnj {
1844567Swnj 	register struct ucb *up;
1854567Swnj COUNT(T_OPEN);
1864497Swnj 
1874567Swnj 	/* enqueue the tcb */
1884497Swnj 
1894567Swnj 	if (netcb.n_tcb_head == NULL) {
1904567Swnj 		netcb.n_tcb_head = tp;
1914567Swnj 		netcb.n_tcb_tail = tp;
1924567Swnj 	} else {
1934567Swnj 		tp->t_tcb_next = netcb.n_tcb_head;
1944567Swnj 		netcb.n_tcb_head->t_tcb_prev = tp;
1954567Swnj 		netcb.n_tcb_head = tp;
1964567Swnj 	}
1974497Swnj 
1984567Swnj 	/* initialize non-zero tcb fields */
1994497Swnj 
2004567Swnj 	tp->t_rcv_next = (struct th *)tp;
2014567Swnj 	tp->t_rcv_prev = (struct th *)tp;
2024567Swnj 	tp->t_xmtime = T_REXMT;
2034567Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi =
2044567Swnj 	              tp->snd_una = tp->iss = netcb.n_iss;
2054567Swnj 	tp->snd_off = tp->iss + 1;
2064567Swnj 	netcb.n_iss += (ISSINCR >> 1) + 1;
2074567Swnj 
2084567Swnj 	/* set timeout for open */
2094567Swnj 
2104567Swnj 	up = tp->t_ucb;
2114567Swnj 	tp->t_init = (up->uc_timeo != 0 ? up->uc_timeo :
2124567Swnj 					(mode == ACTIVE ? T_INIT : 0));
2134567Swnj 	up->uc_timeo = 0;       /* overlays uc_ssize */
2144497Swnj }
2154497Swnj 
2164567Swnj t_close(tp, state)
2174567Swnj 	register struct tcb *tp;
2184567Swnj 	short state;
2194497Swnj {
2204567Swnj 	register struct ucb *up;
2214567Swnj 	register struct th *t;
2224567Swnj 	register struct mbuf *m;
2234567Swnj COUNT(T_CLOSE);
2244497Swnj 
2254567Swnj 	up = tp->t_ucb;
2264497Swnj 
2274567Swnj 	tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist =
2284567Swnj 	    tp->t_finack = 0;
2294497Swnj 
2304567Swnj 	/* delete tcb */
2314567Swnj 
2324567Swnj 	if (tp->t_tcb_prev == NULL)
2334567Swnj 		netcb.n_tcb_head = tp->t_tcb_next;
2344567Swnj 	else
2354567Swnj 		tp->t_tcb_prev->t_tcb_next = tp->t_tcb_next;
2364567Swnj 	if (tp->t_tcb_next == NULL)
2374567Swnj 		netcb.n_tcb_tail = tp->t_tcb_prev;
2384567Swnj 	else
2394567Swnj 		tp->t_tcb_next->t_tcb_prev = tp->t_tcb_prev;
2404567Swnj 
2414567Swnj 	/* free all data on receive and send buffers */
2424567Swnj 
2434567Swnj 	for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next)
2444567Swnj 		m_freem(dtom(t));
2454567Swnj 
2464567Swnj 	if (up->uc_rbuf != NULL) {
2474567Swnj 		m_freem(up->uc_rbuf);
2484567Swnj 		up->uc_rbuf = NULL;
2494567Swnj 	}
250*4592Swnj 	up->uc_rsize = 0;
2514567Swnj 	if (up->uc_sbuf != NULL) {
2524567Swnj 		m_freem(up->uc_sbuf);
2534567Swnj 		up->uc_sbuf = NULL;
2544567Swnj 	}
255*4592Swnj 	up->uc_ssize = 0;
2564567Swnj 	for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) {
2574567Swnj 		m_freem(m);
2584567Swnj 		tp->t_rcv_unack = NULL;
2594567Swnj 	}
2604588Swnj 	m = dtom(tp);
2614588Swnj 	m->m_off = 0;
2624588Swnj 	m_free(m);
2634567Swnj 	up->uc_tcb = NULL;
2644567Swnj 
2654567Swnj 	/* lower buffer allocation and decrement host entry */
2664567Swnj 
2674567Swnj 	netcb.n_lowat -= up->uc_snd + up->uc_rcv + 2;
2684567Swnj 	netcb.n_hiwat = 2 * netcb.n_lowat;
2694567Swnj 	if (up->uc_host != NULL) {
2704567Swnj 		h_free(up->uc_host);
2714567Swnj 		up->uc_host = NULL;
2724567Swnj 	}
2734567Swnj 
2744567Swnj 	/* if user has initiated close (via close call), delete ucb
2754567Swnj 	   entry, otherwise just wakeup so user can issue close call */
2764567Swnj 
2774576Swnj 	if (tp->tc_flags&TC_USR_ABORT)
2784567Swnj         	up->uc_proc = NULL;
2794567Swnj 	else
2804567Swnj         	to_user(up, state);
2814497Swnj }
2824497Swnj 
2834584Swnj sss_snd(tp, m0)
2844584Swnj 	register struct tcb *tp;
2854584Swnj 	struct mbuf *m0;
2864497Swnj {
2874497Swnj 	register struct mbuf *m, *n;
2884584Swnj 	register struct ucb *up = tp->t_ucb;
2894497Swnj 	register off;
2904574Swnj 	seq_t last;
2914497Swnj 
2924497Swnj 	last = tp->snd_off;
2934584Swnj 	for (m = n = m0; m != NULL; m = m->m_next) {
2944497Swnj 		up->uc_ssize++;
2954591Swnj 		if (m->m_off > MMAXOFF)
2964588Swnj 			up->uc_ssize += NMBPG;
2974497Swnj 		last += m->m_len;
2984497Swnj 	}
2994588Swnj 	if ((m = up->uc_sbuf) == NULL)
3004588Swnj 		up->uc_sbuf = n;
3014588Swnj 	else {
3024588Swnj 		while (m->m_next != NULL) {
3034497Swnj 			m = m->m_next;
3044497Swnj 			last += m->m_len;
3054497Swnj 		}
3064591Swnj 		if (m->m_off <= MMAXOFF) {
3074588Swnj 			last += m->m_len;
3084588Swnj 			off = m->m_off + m->m_len;
3094591Swnj 			while (n && n->m_off <= MMAXOFF &&
3104591Swnj 			    (MMAXOFF - off) >= n->m_len) {
3114588Swnj 				bcopy((caddr_t)((int)n + n->m_off),
3124588Swnj 				      (caddr_t)((int)m + off), n->m_len);
3134588Swnj 				m->m_len += n->m_len;
3144588Swnj 				off += n->m_len;
3154588Swnj 				up->uc_ssize--;
3164588Swnj 				n = m_free(n);
3174588Swnj 			}
3184497Swnj 		}
3194497Swnj 		m->m_next = n;
3204588Swnj 	}
3214588Swnj 	if (up->uc_flags & UEOL)
3224497Swnj 		tp->snd_end = last;
3234588Swnj 	if (up->uc_flags & UURG) {
3244497Swnj 		tp->snd_urp = last+1;
3254576Swnj 		tp->tc_flags |= TC_SND_URG;
3264567Swnj 	}
3274497Swnj 	send(tp);
3284567Swnj 	return (SAME);
3294497Swnj }
3304497Swnj 
3314584Swnj tcp_timers(tp, timertype)
3324584Swnj 	register struct tcb *tp;
3334584Swnj 	int timertype;
3344497Swnj {
3354497Swnj 
3364567Swnj COUNT(TCP_TIMERS);
3374584Swnj 	switch (timertype) {
3384497Swnj 
3394567Swnj 	case TINIT:		/* initialization timer */
3404576Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) == 0) {		/* 35 */
3414567Swnj 			t_close(tp, UINTIMO);
3424567Swnj 			return (CLOSED);
3434567Swnj 		}
3444567Swnj 		return (SAME);
3454497Swnj 
3464567Swnj 	case TFINACK:		/* fin-ack timer */
3474567Swnj 		switch (tp->t_state) {
3484497Swnj 
3494567Swnj 		case TIME_WAIT:
3504567Swnj 			/*
3514567Swnj 			 * We can be sure our ACK of foreign FIN was rcvd,
3524567Swnj 			 * and can close if no data left for user.
3534567Swnj 			 */
3544567Swnj 			if (rcv_empty(tp)) {
3554567Swnj 				t_close(tp, UCLOSED);		/* 14 */
3564567Swnj 				return (CLOSED);
3574567Swnj 			}
3584567Swnj 			return (RCV_WAIT);			/* 17 */
3594497Swnj 
3604567Swnj 		case CLOSING1:
3614576Swnj 			tp->tc_flags |= TC_WAITED_2_ML;
3624567Swnj 			return (SAME);
3634497Swnj 
3644567Swnj 		default:
3654567Swnj 			return (SAME);
3664567Swnj 		}
3674497Swnj 
3684567Swnj 	case TREXMT:		/* retransmission timer */
3694567Swnj 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
3704567Swnj 			/*
3714567Swnj 			 * Set up for a retransmission, increase rexmt time
3724567Swnj 			 * in case of multiple retransmissions.
3734567Swnj 			 */
3744567Swnj 			tp->snd_nxt = tp->snd_una;
3754576Swnj 			tp->tc_flags |= TC_REXMT;
3764567Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
3774567Swnj 			if (tp->t_xmtime > T_REMAX)
3784567Swnj 				tp->t_xmtime = T_REMAX;
3794567Swnj 			send(tp);
3804567Swnj 		}
3814567Swnj 		return (SAME);
3824497Swnj 
3834567Swnj 	case TREXMTTL:		/* retransmit too long */
3844567Swnj 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
3854567Swnj 			to_user(tp->t_ucb, URXTIMO);
3864567Swnj 		/*
3874567Swnj 		 * If user has already closed, abort the connection.
3884567Swnj 		 */
3894576Swnj 		if (tp->tc_flags & TC_USR_CLOSED) {
3904567Swnj 			t_close(tp, URXTIMO);
3914567Swnj 			return (CLOSED);
3924567Swnj 		}
3934567Swnj 		return (SAME);
3944497Swnj 
3954567Swnj 	case TPERSIST:		/* persist timer */
3964567Swnj 		/*
3974567Swnj 		 * Force a byte send through closed window.
3984567Swnj 		 */
3994576Swnj 		tp->tc_flags |= TC_FORCE_ONE;
4004567Swnj 		send(tp);
4014567Swnj 		return (SAME);
4024567Swnj 	}
4034567Swnj 	panic("tcp_timers");
4044497Swnj }
4054497Swnj 
4064567Swnj /* THIS ROUTINE IS A CROCK */
4074567Swnj to_user(up, state)
4084567Swnj 	register struct ucb *up;
4094567Swnj 	register short state;
4104497Swnj {
4114567Swnj COUNT(TO_USER);
4124497Swnj 
4134567Swnj 	up->uc_state |= state;
4144567Swnj 	netwakeup(up);
4154567Swnj   	if (state == UURGENT)
4164567Swnj 		psignal(up->uc_proc, SIGURG);
4174497Swnj }
4184584Swnj 
4194584Swnj #ifdef TCPDEBUG
4204584Swnj tcp_prt(tdp)
4214584Swnj 	register struct tcp_debug *tdp;
4224584Swnj {
4234584Swnj COUNT(TCP_PRT);
4244584Swnj 
4254584Swnj 	printf("TCP(%X) %s X %s",
4264584Swnj 	    tdp->td_tcb, tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
4274584Swnj 	if (tdp->td_inp == ISTIMER)
4284584Swnj 		printf("(%s)", tcptimers[tdp->td_tim]);
4294584Swnj 	printf(" --> %s",
4304584Swnj 	    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
4314584Swnj 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
4324584Swnj 	if (tdp->td_new < 0)
4334584Swnj 		printf(" (FAILED)");
4344584Swnj 	printf("\n");
4354584Swnj }
4364584Swnj #endif
437