xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 5075)
1 /* tcp_usrreq.c 1.35 81/11/25 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../h/protosw.h"
9 #include "../net/inet.h"
10 #include "../net/inet_pcb.h"
11 #include "../net/inet_systm.h"
12 #include "../net/if.h"
13 #include "../net/imp.h"
14 #include "../net/ip.h"
15 #include "../net/ip_var.h"
16 #include "../net/tcp.h"
17 #include "../net/tcp_fsm.h"
18 #include "../net/tcp_var.h"
19 #include "/usr/include/errno.h"
20 
21 struct	tcpcb *tcp_newtcpcb();
22 /*
23  * Process a TCP user request for tcp tb.  If this is a send request
24  * then m is the mbuf chain of send data.  If this is a timer expiration
25  * (called from the software clock routine), then timertype tells which timer.
26  */
27 tcp_usrreq(so, req, m, addr)
28 	struct socket *so;
29 	int req;
30 	struct mbuf *m;
31 	caddr_t addr;
32 {
33 	register struct inpcb *inp = sotoinpcb(so);
34 	register struct tcpcb *tp;
35 	int s = splnet();
36 	int error = 0;
37 	struct tcpiphdr ti;
38 COUNT(TCP_USRREQ);
39 
40 	/*
41 	 * Make sure attached.  If not,
42 	 * only PRU_ATTACH is valid.
43 	 */
44 	if (inp == 0 && req != PRU_ATTACH)
45 		splx(s);
46 		return (EINVAL);
47 	}
48 	if (inp) {
49 		tp = intotcpcb(inp);
50 #ifdef KPROF
51 		tcp_acounts[tp->t_state][req]++;
52 #endif
53 	}
54 	switch (req) {
55 
56 	case PRU_ATTACH:
57 		if (inp) {
58 			error = EISCONN;
59 			break;
60 		}
61 		error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
62 		if (error)
63 			break;
64 		inp = (struct inpcb *)so->so_pcb;
65 		if (so->so_options & SO_ACCEPTCONN) {
66 			tp = tcp_newtcpcb(inp);
67 			if (tp == 0) {
68 				in_pcbfree(inp);
69 				error = ENOBUFS;
70 				break;
71 			}
72 			tp->t_state = TCPS_LISTEN;
73 		} else
74 			tp->t_state = TCPS_CLOSED;
75 		break;
76 
77 	case PRU_DETACH:
78 		break;
79 
80 	case PRU_CONNECT:
81 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
82 		if (error)
83 			break;
84 		tp = tcp_newtcpcb(inp);
85 		if (tp == 0) {
86 			inp->inp_faddr.s_addr = 0;
87 			error = ENOBUFS;
88 			break;
89 		}
90 		tp->t_inpcb = inp;
91 		inp->inp_ppcb = (caddr_t)tp;
92 		soisconnecting(so);
93 		tp->t_state = TCPS_SYN_SENT;
94 		tcp_output(tp);
95 		break;
96 
97 	case PRU_ACCEPT:
98 		soisconnected(so);
99 		break;
100 
101 	case PRU_DISCONNECT:
102 		if (tp->t_state < TCPS_ESTABLISHED)
103 			tcp_close(tp);
104 		else {
105 			soisdisconnecting(so);
106 			tcp_output(tp);
107 		}
108 		break;
109 
110 	case PRU_SHUTDOWN:
111 		socantsndmore(so);
112 		switch (tp->t_state) {
113 
114 		case TCPS_LISTEN:
115 		case TCPS_SYN_SENT:
116 			tp->t_state = TCPS_CLOSED;
117 			break;
118 
119 		case TCPS_SYN_RCVD:
120 		case TCPS_ESTAB:
121 			tp->t_state = TCPS_FIN_WAIT_1;
122 			tcp_output(tp);
123 			break;
124 
125 		case TCPS_CLOSE_WAIT:
126 			tp->t_state = TCPS_LAST_ACK;
127 			tcp_output(tp);
128 			break;
129 		}
130 		break;
131 
132 	case PRU_RCVD:
133 		if (tp->t_state < TCPS_ESTABLISHED) {
134 			error = ENOTCONN;
135 			break;
136 		}
137 		tcp_output(tp);
138 		break;
139 
140 	case PRU_SEND:
141 		if (tp->t_state < TCPS_ESTABLISHED) {
142 			error = ENOTCONN;
143 			break;
144 		}
145 		if (tp->t_state > TCPS_CLOSE_WAIT) {
146 			error = EISDISCONN;
147 			m_freem(m);
148 			break;
149 		}
150 		sbappend(&so->so_snd, m);
151 		if (tp->t_options & TO_EOL)
152 			tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
153 		if (tp->t_options & TO_URG)
154 			tp->snd_urp = tp->snd_una + so->so_snd.sb_cc + 1;
155 		tcp_output(tp);
156 		break;
157 
158 	case PRU_ABORT:
159 		tcp_drop(tp, ECONNABORTED);
160 		break;
161 
162 	case PRU_CONTROL:
163 		error = EOPNOTSUPP;
164 		break;
165 
166 	case PRU_SLOWTIMO:
167 		tcp_timers(tp, (int)addr);
168 		break;
169 
170 	default:
171 		panic("tcp_usrreq");
172 	}
173 	splx(s);
174 	return (error);
175 }
176