xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 5075)
1*5075Swnj /* tcp_usrreq.c 1.35 81/11/25 */
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();
364809Swnj 	int error = 0;
37*5075Swnj 	struct tcpiphdr ti;
384567Swnj COUNT(TCP_USRREQ);
394497Swnj 
404886Swnj 	/*
414886Swnj 	 * Make sure attached.  If not,
424886Swnj 	 * only PRU_ATTACH is valid.
434886Swnj 	 */
44*5075Swnj 	if (inp == 0 && req != PRU_ATTACH)
45*5075Swnj 		splx(s);
46*5075Swnj 		return (EINVAL);
47*5075Swnj 	}
48*5075Swnj 	if (inp) {
494911Swnj 		tp = intotcpcb(inp);
504731Swnj #ifdef KPROF
51*5075Swnj 		tcp_acounts[tp->t_state][req]++;
524731Swnj #endif
534911Swnj 	}
544809Swnj 	switch (req) {
554497Swnj 
564809Swnj 	case PRU_ATTACH:
574954Swnj 		if (inp) {
584809Swnj 			error = EISCONN;
594911Swnj 			break;
604886Swnj 		}
614954Swnj 		error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
62*5075Swnj 		if (error)
634954Swnj 			break;
644954Swnj 		inp = (struct inpcb *)so->so_pcb;
655062Swnj 		if (so->so_options & SO_ACCEPTCONN) {
665062Swnj 			tp = tcp_newtcpcb(inp);
675062Swnj 			if (tp == 0) {
68*5075Swnj 				in_pcbfree(inp);
695062Swnj 				error = ENOBUFS;
705062Swnj 				break;
715062Swnj 			}
72*5075Swnj 			tp->t_state = TCPS_LISTEN;
735062Swnj 		} else
74*5075Swnj 			tp->t_state = TCPS_CLOSED;
754567Swnj 		break;
764497Swnj 
774809Swnj 	case PRU_DETACH:
784809Swnj 		break;
794809Swnj 
804809Swnj 	case PRU_CONNECT:
814954Swnj 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
824954Swnj 		if (error)
834886Swnj 			break;
845062Swnj 		tp = tcp_newtcpcb(inp);
855062Swnj 		if (tp == 0) {
865062Swnj 			inp->inp_faddr.s_addr = 0;
875062Swnj 			error = ENOBUFS;
885062Swnj 			break;
895062Swnj 		}
905062Swnj 		tp->t_inpcb = inp;
915062Swnj 		inp->inp_ppcb = (caddr_t)tp;
924886Swnj 		soisconnecting(so);
93*5075Swnj 		tp->t_state = TCPS_SYN_SENT;
94*5075Swnj 		tcp_output(tp);
954567Swnj 		break;
964497Swnj 
974925Swnj 	case PRU_ACCEPT:
984954Swnj 		soisconnected(so);
994954Swnj 		break;
1004925Swnj 
1014809Swnj 	case PRU_DISCONNECT:
102*5075Swnj 		if (tp->t_state < TCPS_ESTABLISHED)
103*5075Swnj 			tcp_close(tp);
1044886Swnj 		else {
1054886Swnj 			soisdisconnecting(so);
106*5075Swnj 			tcp_output(tp);
1074886Swnj 		}
1084809Swnj 		break;
1094809Swnj 
1104809Swnj 	case PRU_SHUTDOWN:
111*5075Swnj 		socantsndmore(so);
112*5075Swnj 		switch (tp->t_state) {
1134497Swnj 
1145066Swnj 		case TCPS_LISTEN:
1155066Swnj 		case TCPS_SYN_SENT:
116*5075Swnj 			tp->t_state = TCPS_CLOSED;
1174731Swnj 			break;
1184731Swnj 
1195066Swnj 		case TCPS_SYN_RCVD:
120*5075Swnj 		case TCPS_ESTAB:
121*5075Swnj 			tp->t_state = TCPS_FIN_WAIT_1;
122*5075Swnj 			tcp_output(tp);
123*5075Swnj 			break;
124*5075Swnj 
1255066Swnj 		case TCPS_CLOSE_WAIT:
126*5075Swnj 			tp->t_state = TCPS_LAST_ACK;
127*5075Swnj 			tcp_output(tp);
1284731Swnj 			break;
1294731Swnj 		}
1304567Swnj 		break;
1314497Swnj 
1324809Swnj 	case PRU_RCVD:
133*5075Swnj 		if (tp->t_state < TCPS_ESTABLISHED) {
134*5075Swnj 			error = ENOTCONN;
135*5075Swnj 			break;
136*5075Swnj 		}
137*5075Swnj 		tcp_output(tp);
1384567Swnj 		break;
1394497Swnj 
1404809Swnj 	case PRU_SEND:
141*5075Swnj 		if (tp->t_state < TCPS_ESTABLISHED) {
142*5075Swnj 			error = ENOTCONN;
1434731Swnj 			break;
144*5075Swnj 		}
145*5075Swnj 		if (tp->t_state > TCPS_CLOSE_WAIT) {
146*5075Swnj 			error = EISDISCONN;
1474809Swnj 			m_freem(m);
1484731Swnj 			break;
1494731Swnj 		}
150*5075Swnj 		sbappend(&so->so_snd, m);
151*5075Swnj 		if (tp->t_options & TO_EOL)
152*5075Swnj 			tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
153*5075Swnj 		if (tp->t_options & TO_URG)
154*5075Swnj 			tp->snd_urp = tp->snd_una + so->so_snd.sb_cc + 1;
155*5075Swnj 		tcp_output(tp);
1564567Swnj 		break;
1574567Swnj 
1584809Swnj 	case PRU_ABORT:
159*5075Swnj 		tcp_drop(tp, ECONNABORTED);
1604567Swnj 		break;
1614567Swnj 
1624809Swnj 	case PRU_CONTROL:
1634886Swnj 		error = EOPNOTSUPP;
1644809Swnj 		break;
1654809Swnj 
1664809Swnj 	case PRU_SLOWTIMO:
167*5075Swnj 		tcp_timers(tp, (int)addr);
1684809Swnj 		break;
1694809Swnj 
1704731Swnj 	default:
1714731Swnj 		panic("tcp_usrreq");
1724567Swnj 	}
1734567Swnj 	splx(s);
1744886Swnj 	return (error);
1754497Swnj }
176