xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 5066)
1*5066Swnj /* tcp_usrreq.c 1.34 81/11/24 */
24567Swnj 
34497Swnj #include "../h/param.h"
44567Swnj #include "../h/systm.h"
54664Swnj #include "../h/mbuf.h"
64664Swnj #include "../h/socket.h"
74809Swnj #include "../h/socketvar.h"
84809Swnj #include "../h/protosw.h"
94809Swnj #include "../net/inet.h"
104886Swnj #include "../net/inet_pcb.h"
114809Swnj #include "../net/inet_systm.h"
124954Swnj #include "../net/if.h"
134809Swnj #include "../net/imp.h"
144809Swnj #include "../net/ip.h"
154900Swnj #include "../net/ip_var.h"
164809Swnj #include "../net/tcp.h"
174809Swnj #include "../net/tcp_fsm.h"
184809Swnj #include "../net/tcp_var.h"
194809Swnj #include "/usr/include/errno.h"
204497Swnj 
214954Swnj struct	tcpcb *tcp_newtcpcb();
224734Swnj /*
234731Swnj  * Process a TCP user request for tcp tb.  If this is a send request
244731Swnj  * then m is the mbuf chain of send data.  If this is a timer expiration
254731Swnj  * (called from the software clock routine), then timertype tells which timer.
264731Swnj  */
274809Swnj tcp_usrreq(so, req, m, addr)
284809Swnj 	struct socket *so;
294809Swnj 	int req;
304731Swnj 	struct mbuf *m;
314809Swnj 	caddr_t addr;
324497Swnj {
334886Swnj 	register struct inpcb *inp = sotoinpcb(so);
344911Swnj 	register struct tcpcb *tp;
354567Swnj 	int s = splnet();
364567Swnj 	register int nstate;
374809Swnj 	int error = 0;
384567Swnj COUNT(TCP_USRREQ);
394497Swnj 
404886Swnj 	/*
414886Swnj 	 * Make sure attached.  If not,
424886Swnj 	 * only PRU_ATTACH is valid.
434886Swnj 	 */
444911Swnj 	if (inp == 0) {
454886Swnj 		if (req != PRU_ATTACH) {
464886Swnj 			splx(s);
474886Swnj 			return (EINVAL);
484886Swnj 		}
494911Swnj 	} else {
504911Swnj 		tp = intotcpcb(inp);
514911Swnj 		nstate = tp->t_state;
524731Swnj #ifdef KPROF
534911Swnj 		tcp_acounts[nstate][req]++;
544731Swnj #endif
554911Swnj 	}
564911Swnj 
574809Swnj 	switch (req) {
584497Swnj 
594809Swnj 	case PRU_ATTACH:
604954Swnj 		if (inp) {
614809Swnj 			error = EISCONN;
624911Swnj 			break;
634886Swnj 		}
644954Swnj 		error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
654954Swnj 		if (error) {
664967Swnj 			(void) m_free(dtom(tp));
674954Swnj 			break;
684954Swnj 		}
694954Swnj 		inp = (struct inpcb *)so->so_pcb;
705062Swnj 		if (so->so_options & SO_ACCEPTCONN) {
715062Swnj 			tp = tcp_newtcpcb(inp);
725062Swnj 			if (tp == 0) {
735062Swnj 				error = ENOBUFS;
745062Swnj 				break;
755062Swnj 			}
764886Swnj 			nstate = LISTEN;
775062Swnj 		} else
784886Swnj 			nstate = CLOSED;
794567Swnj 		break;
804497Swnj 
814809Swnj 	case PRU_DETACH:
824809Swnj 		break;
834809Swnj 
844809Swnj 	case PRU_CONNECT:
854954Swnj 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
864954Swnj 		if (error)
874886Swnj 			break;
885062Swnj 		tp = tcp_newtcpcb(inp);
895062Swnj 		if (tp == 0) {
905062Swnj 			inp->inp_faddr.s_addr = 0;
915062Swnj 			error = ENOBUFS;
925062Swnj 			break;
935062Swnj 		}
945062Swnj 		tp->t_inpcb = inp;
955062Swnj 		inp->inp_ppcb = (caddr_t)tp;
964911Swnj 		(void) tcp_sndctl(tp);
974567Swnj 		nstate = SYN_SENT;
984886Swnj 		soisconnecting(so);
994567Swnj 		break;
1004497Swnj 
1014925Swnj 	case PRU_ACCEPT:
1024954Swnj 		soisconnected(so);
1034954Swnj 		break;
1044925Swnj 
1054809Swnj 	case PRU_DISCONNECT:
1064886Swnj 		if (nstate < ESTAB)
1074911Swnj 			tcp_disconnect(tp);
1084886Swnj 		else {
1094886Swnj 			tp->tc_flags |= TC_SND_FIN;
1104911Swnj 			(void) tcp_sndctl(tp);
1114886Swnj 			soisdisconnecting(so);
1124886Swnj 		}
1134809Swnj 		break;
1144809Swnj 
1154809Swnj 	case PRU_SHUTDOWN:
1164731Swnj 		switch (nstate) {
1174497Swnj 
118*5066Swnj 		case TCPS_LISTEN:
119*5066Swnj 		case TCPS_SYN_SENT:
120*5066Swnj 			nstate = TCPS_CLOSED;
1214731Swnj 			break;
1224731Swnj 
123*5066Swnj 		case TCPS_SYN_RCVD:
124*5066Swnj 		case TCPS_ESTABLISHED:
125*5066Swnj 		case TCPS_CLOSE_WAIT:
1264731Swnj 			tp->tc_flags |= TC_SND_FIN;
1274911Swnj 			(void) tcp_sndctl(tp);
1284731Swnj 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
1294731Swnj 			break;
1304731Swnj 
131*5066Swnj 		case TCPS_FIN_W1:
132*5066Swnj 		case TCPS_FIN_W2:
133*5066Swnj 		case TCPS_TIME_WAIT:
134*5066Swnj 		case TCPS_CLOSING:
135*5066Swnj 		case TCPS_LAST_ACK:
136*5066Swnj 		case TCPS_RCV_WAIT:
1374731Swnj 			break;
1384731Swnj 
1394731Swnj 		default:
1404731Swnj 			goto bad;
1414731Swnj 		}
1424567Swnj 		break;
1434497Swnj 
1444809Swnj 	case PRU_RCVD:
145*5066Swnj 		if (nstate < TCPS_ESTAB)
1464731Swnj 			goto bad;
1474734Swnj 		tcp_sndwin(tp);
148*5066Swnj 		if (nstate == TCPS_RCV_WAIT && rcv_empty(tp))
149*5066Swnj 			nstate = TCPS_CLOSED;
1504567Swnj 		break;
1514497Swnj 
1524809Swnj 	case PRU_SEND:
1534731Swnj 		switch (nstate) {
1544567Swnj 
1554731Swnj 		case ESTAB:
1564731Swnj 		case CLOSE_WAIT:
1574886Swnj 			tcp_usrsend(tp, m);
1584731Swnj 			break;
1594731Swnj 
1604731Swnj 		default:
1614731Swnj 			if (nstate < ESTAB)
1624731Swnj 				goto bad;
1634809Swnj 			m_freem(m);
1644886Swnj 			error = ENOTCONN;
1654731Swnj 			break;
1664731Swnj 		}
1674567Swnj 		break;
1684567Swnj 
1694809Swnj 	case PRU_ABORT:
1704886Swnj 		tcp_abort(tp);
1714567Swnj 		nstate = CLOSED;
1724567Swnj 		break;
1734567Swnj 
1744809Swnj 	case PRU_CONTROL:
1754886Swnj 		error = EOPNOTSUPP;
1764809Swnj 		break;
1774809Swnj 
1784809Swnj 	case PRU_SLOWTIMO:
1794809Swnj 		switch (nstate) {
1804809Swnj 
1814809Swnj 		case 0:
1824809Swnj 		case CLOSED:
1834809Swnj 		case LISTEN:
1844809Swnj 			goto bad;
1854809Swnj 
1864809Swnj 		default:
1874809Swnj 			nstate = tcp_timers(tp, (int)addr);
1884809Swnj 		}
1894809Swnj 		break;
1904809Swnj 
1914731Swnj 	default:
1924731Swnj 		panic("tcp_usrreq");
1934731Swnj 	bad:
1944731Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
1954809Swnj 		    tp, tp->t_state, req);
1964731Swnj 		nstate = EFAILEC;
1974567Swnj 		break;
1984567Swnj 	}
1994567Swnj 	switch (nstate) {
2004567Swnj 
2014584Swnj 	case CLOSED:
2024567Swnj 	case SAME:
2034567Swnj 		break;
2044567Swnj 
2054567Swnj 	case EFAILEC:
2064731Swnj 		if (m)
2074731Swnj 			m_freem(dtom(m));
2084567Swnj 		break;
2094567Swnj 
2104567Swnj 	default:
2114567Swnj 		tp->t_state = nstate;
2124567Swnj 		break;
2134567Swnj 	}
2144567Swnj 	splx(s);
2154886Swnj 	return (error);
2164497Swnj }
2174497Swnj 
2184954Swnj struct tcpcb *
2195062Swnj tcp_newtcpcb(inp)
2205062Swnj 	struct inpcb *inp;
2214809Swnj {
2224954Swnj 	struct mbuf *m = m_getclr(0);
2234954Swnj 	register struct tcpcb *tp;
2244954Swnj COUNT(TCP_NEWTCPCB);
2254497Swnj 
2264954Swnj 	if (m == 0)
2274954Swnj 		return (0);
2284954Swnj 	tp = mtod(m, struct tcpcb *);
2294954Swnj 
2304682Swnj 	/*
2314886Swnj 	 * Make empty reassembly queue.
2324682Swnj 	 */
2334886Swnj 	tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
2344497Swnj 
2354682Swnj 	/*
2364886Swnj 	 * Initialize sequence numbers and round trip retransmit timer.
2374682Swnj 	 */
2384567Swnj 	tp->t_xmtime = T_REXMT;
2394682Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
2404682Swnj 	    tp->iss = tcp_iss;
2414567Swnj 	tp->snd_off = tp->iss + 1;
2424664Swnj 	tcp_iss += (ISSINCR >> 1) + 1;
2435062Swnj 
2445062Swnj 	/*
2455062Swnj 	 * Hook to inpcb.
2465062Swnj 	 */
2475062Swnj 	tp->t_inpcb = inp;
2485062Swnj 	inp->inp_ppcb = (caddr_t)tp;
2494954Swnj 	return (tp);
2504497Swnj }
2514497Swnj 
2524886Swnj tcp_disconnect(tp)
2534886Swnj 	register struct tcpcb *tp;
2544886Swnj {
2554886Swnj 	register struct tcpiphdr *t;
2564886Swnj 
2574954Swnj COUNT(TCP_DISCONNECT);
2584734Swnj 	tcp_tcancel(tp);
2594886Swnj 	t = tp->seg_next;
2604900Swnj 	for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
2614567Swnj 		m_freem(dtom(t));
2624886Swnj 	tcp_drainunack(tp);
2634734Swnj 	if (tp->t_template) {
2644911Swnj 		(void) m_free(dtom(tp->t_template));
2654734Swnj 		tp->t_template = 0;
2664664Swnj 	}
2674886Swnj 	in_pcbfree(tp->t_inpcb);
2685062Swnj 	(void) m_free(dtom(tp));
2694497Swnj }
2704497Swnj 
2714911Swnj tcp_abort(tp)
2724911Swnj 	register struct tcpcb *tp;
2734886Swnj {
2744886Swnj 
2754954Swnj COUNT(TCP_ABORT);
2764886Swnj 	switch (tp->t_state) {
2774886Swnj 
2784886Swnj 	case SYN_RCVD:
2794886Swnj 	case ESTAB:
2804886Swnj 	case FIN_W1:
2814886Swnj 	case FIN_W2:
2824886Swnj 	case CLOSE_WAIT:
2834886Swnj 		tp->tc_flags |= TC_SND_RST;
2844886Swnj 		tcp_sndnull(tp);
2854886Swnj 	}
2864911Swnj 	soisdisconnected(tp->t_inpcb->inp_socket);
2875062Swnj 	tcp_disconnect(tp);
2884886Swnj }
2894886Swnj 
2904682Swnj /*
2914734Swnj  * Send data queue headed by m0 into the protocol.
2924682Swnj  */
2934678Swnj tcp_usrsend(tp, m0)
2944886Swnj 	register struct tcpcb *tp;
2954584Swnj 	struct mbuf *m0;
2964497Swnj {
2974886Swnj 	register struct socket *so = tp->t_inpcb->inp_socket;
2984682Swnj COUNT(TCP_USRSEND);
2994497Swnj 
3004886Swnj 	sbappend(&so->so_snd, m0);
3014809Swnj 	if (tp->t_options & TO_EOL)
3024886Swnj 		tp->snd_end = tp->snd_off + so->so_snd.sb_cc;
3034809Swnj 	if (tp->t_options & TO_URG) {
3044886Swnj 		tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1;
3054576Swnj 		tp->tc_flags |= TC_SND_URG;
3064567Swnj 	}
3074911Swnj 	(void) tcp_send(tp);
3084497Swnj }
3094497Swnj 
3104911Swnj /*ARGSUSED*/
3114886Swnj tcp_sense(m)
3124886Swnj 	struct mbuf *m;
3134886Swnj {
3144886Swnj 
3154954Swnj COUNT(TCP_SENSE);
3164886Swnj 	return (EOPNOTSUPP);
3174886Swnj }
3184886Swnj 
3195062Swnj tcp_drop(tp, errno)
3204911Swnj 	struct tcpcb *tp;
3214809Swnj 	int errno;
3224497Swnj {
3234911Swnj 	struct socket *so = tp->t_inpcb->inp_socket;
3244954Swnj 
3254911Swnj COUNT(TCP_ERROR);
3264809Swnj 	so->so_error = errno;
3274886Swnj 	sorwakeup(so);
3284886Swnj 	sowwakeup(so);
3295062Swnj 	tcp_disconnect(tp);
3304497Swnj }
3314584Swnj 
332*5066Swnj tcp_drain()
3334670Swnj {
334*5066Swnj 	register struct inpcb *ip;
3354670Swnj 
336*5066Swnj COUNT(TCP_DRAIN);
337*5066Swnj 	for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next)
338*5066Swnj 		tcp_drainunack(intotcpcb(ip));
3394670Swnj }
3404670Swnj 
341*5066Swnj tcp_drainunack(tp)
342*5066Swnj 	register struct tcpcb *tp;
3434670Swnj {
344*5066Swnj 	register struct mbuf *m;
3454670Swnj 
346*5066Swnj COUNT(TCP_DRAINUNACK);
347*5066Swnj 	for (m = tp->seg_unack; m; m = m->m_act)
348*5066Swnj 		m_freem(m);
349*5066Swnj 	tp->seg_unack = 0;
3504670Swnj }
351*5066Swnj 
352*5066Swnj tcp_ctlinput(m)
353*5066Swnj 	struct mbuf *m;
3544682Swnj {
3554682Swnj 
356*5066Swnj COUNT(TCP_CTLINPUT);
357*5066Swnj 	m_freem(m);
3584682Swnj }
359