xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 5066)
1 /* tcp_usrreq.c 1.34 81/11/24 */
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 	register int nstate;
37 	int error = 0;
38 COUNT(TCP_USRREQ);
39 
40 	/*
41 	 * Make sure attached.  If not,
42 	 * only PRU_ATTACH is valid.
43 	 */
44 	if (inp == 0) {
45 		if (req != PRU_ATTACH) {
46 			splx(s);
47 			return (EINVAL);
48 		}
49 	} else {
50 		tp = intotcpcb(inp);
51 		nstate = tp->t_state;
52 #ifdef KPROF
53 		tcp_acounts[nstate][req]++;
54 #endif
55 	}
56 
57 	switch (req) {
58 
59 	case PRU_ATTACH:
60 		if (inp) {
61 			error = EISCONN;
62 			break;
63 		}
64 		error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
65 		if (error) {
66 			(void) m_free(dtom(tp));
67 			break;
68 		}
69 		inp = (struct inpcb *)so->so_pcb;
70 		if (so->so_options & SO_ACCEPTCONN) {
71 			tp = tcp_newtcpcb(inp);
72 			if (tp == 0) {
73 				error = ENOBUFS;
74 				break;
75 			}
76 			nstate = LISTEN;
77 		} else
78 			nstate = CLOSED;
79 		break;
80 
81 	case PRU_DETACH:
82 		break;
83 
84 	case PRU_CONNECT:
85 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
86 		if (error)
87 			break;
88 		tp = tcp_newtcpcb(inp);
89 		if (tp == 0) {
90 			inp->inp_faddr.s_addr = 0;
91 			error = ENOBUFS;
92 			break;
93 		}
94 		tp->t_inpcb = inp;
95 		inp->inp_ppcb = (caddr_t)tp;
96 		(void) tcp_sndctl(tp);
97 		nstate = SYN_SENT;
98 		soisconnecting(so);
99 		break;
100 
101 	case PRU_ACCEPT:
102 		soisconnected(so);
103 		break;
104 
105 	case PRU_DISCONNECT:
106 		if (nstate < ESTAB)
107 			tcp_disconnect(tp);
108 		else {
109 			tp->tc_flags |= TC_SND_FIN;
110 			(void) tcp_sndctl(tp);
111 			soisdisconnecting(so);
112 		}
113 		break;
114 
115 	case PRU_SHUTDOWN:
116 		switch (nstate) {
117 
118 		case TCPS_LISTEN:
119 		case TCPS_SYN_SENT:
120 			nstate = TCPS_CLOSED;
121 			break;
122 
123 		case TCPS_SYN_RCVD:
124 		case TCPS_ESTABLISHED:
125 		case TCPS_CLOSE_WAIT:
126 			tp->tc_flags |= TC_SND_FIN;
127 			(void) tcp_sndctl(tp);
128 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
129 			break;
130 
131 		case TCPS_FIN_W1:
132 		case TCPS_FIN_W2:
133 		case TCPS_TIME_WAIT:
134 		case TCPS_CLOSING:
135 		case TCPS_LAST_ACK:
136 		case TCPS_RCV_WAIT:
137 			break;
138 
139 		default:
140 			goto bad;
141 		}
142 		break;
143 
144 	case PRU_RCVD:
145 		if (nstate < TCPS_ESTAB)
146 			goto bad;
147 		tcp_sndwin(tp);
148 		if (nstate == TCPS_RCV_WAIT && rcv_empty(tp))
149 			nstate = TCPS_CLOSED;
150 		break;
151 
152 	case PRU_SEND:
153 		switch (nstate) {
154 
155 		case ESTAB:
156 		case CLOSE_WAIT:
157 			tcp_usrsend(tp, m);
158 			break;
159 
160 		default:
161 			if (nstate < ESTAB)
162 				goto bad;
163 			m_freem(m);
164 			error = ENOTCONN;
165 			break;
166 		}
167 		break;
168 
169 	case PRU_ABORT:
170 		tcp_abort(tp);
171 		nstate = CLOSED;
172 		break;
173 
174 	case PRU_CONTROL:
175 		error = EOPNOTSUPP;
176 		break;
177 
178 	case PRU_SLOWTIMO:
179 		switch (nstate) {
180 
181 		case 0:
182 		case CLOSED:
183 		case LISTEN:
184 			goto bad;
185 
186 		default:
187 			nstate = tcp_timers(tp, (int)addr);
188 		}
189 		break;
190 
191 	default:
192 		panic("tcp_usrreq");
193 	bad:
194 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
195 		    tp, tp->t_state, req);
196 		nstate = EFAILEC;
197 		break;
198 	}
199 	switch (nstate) {
200 
201 	case CLOSED:
202 	case SAME:
203 		break;
204 
205 	case EFAILEC:
206 		if (m)
207 			m_freem(dtom(m));
208 		break;
209 
210 	default:
211 		tp->t_state = nstate;
212 		break;
213 	}
214 	splx(s);
215 	return (error);
216 }
217 
218 struct tcpcb *
219 tcp_newtcpcb(inp)
220 	struct inpcb *inp;
221 {
222 	struct mbuf *m = m_getclr(0);
223 	register struct tcpcb *tp;
224 COUNT(TCP_NEWTCPCB);
225 
226 	if (m == 0)
227 		return (0);
228 	tp = mtod(m, struct tcpcb *);
229 
230 	/*
231 	 * Make empty reassembly queue.
232 	 */
233 	tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
234 
235 	/*
236 	 * Initialize sequence numbers and round trip retransmit timer.
237 	 */
238 	tp->t_xmtime = T_REXMT;
239 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
240 	    tp->iss = tcp_iss;
241 	tp->snd_off = tp->iss + 1;
242 	tcp_iss += (ISSINCR >> 1) + 1;
243 
244 	/*
245 	 * Hook to inpcb.
246 	 */
247 	tp->t_inpcb = inp;
248 	inp->inp_ppcb = (caddr_t)tp;
249 	return (tp);
250 }
251 
252 tcp_disconnect(tp)
253 	register struct tcpcb *tp;
254 {
255 	register struct tcpiphdr *t;
256 
257 COUNT(TCP_DISCONNECT);
258 	tcp_tcancel(tp);
259 	t = tp->seg_next;
260 	for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
261 		m_freem(dtom(t));
262 	tcp_drainunack(tp);
263 	if (tp->t_template) {
264 		(void) m_free(dtom(tp->t_template));
265 		tp->t_template = 0;
266 	}
267 	in_pcbfree(tp->t_inpcb);
268 	(void) m_free(dtom(tp));
269 }
270 
271 tcp_abort(tp)
272 	register struct tcpcb *tp;
273 {
274 
275 COUNT(TCP_ABORT);
276 	switch (tp->t_state) {
277 
278 	case SYN_RCVD:
279 	case ESTAB:
280 	case FIN_W1:
281 	case FIN_W2:
282 	case CLOSE_WAIT:
283 		tp->tc_flags |= TC_SND_RST;
284 		tcp_sndnull(tp);
285 	}
286 	soisdisconnected(tp->t_inpcb->inp_socket);
287 	tcp_disconnect(tp);
288 }
289 
290 /*
291  * Send data queue headed by m0 into the protocol.
292  */
293 tcp_usrsend(tp, m0)
294 	register struct tcpcb *tp;
295 	struct mbuf *m0;
296 {
297 	register struct socket *so = tp->t_inpcb->inp_socket;
298 COUNT(TCP_USRSEND);
299 
300 	sbappend(&so->so_snd, m0);
301 	if (tp->t_options & TO_EOL)
302 		tp->snd_end = tp->snd_off + so->so_snd.sb_cc;
303 	if (tp->t_options & TO_URG) {
304 		tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1;
305 		tp->tc_flags |= TC_SND_URG;
306 	}
307 	(void) tcp_send(tp);
308 }
309 
310 /*ARGSUSED*/
311 tcp_sense(m)
312 	struct mbuf *m;
313 {
314 
315 COUNT(TCP_SENSE);
316 	return (EOPNOTSUPP);
317 }
318 
319 tcp_drop(tp, errno)
320 	struct tcpcb *tp;
321 	int errno;
322 {
323 	struct socket *so = tp->t_inpcb->inp_socket;
324 
325 COUNT(TCP_ERROR);
326 	so->so_error = errno;
327 	sorwakeup(so);
328 	sowwakeup(so);
329 	tcp_disconnect(tp);
330 }
331 
332 tcp_drain()
333 {
334 	register struct inpcb *ip;
335 
336 COUNT(TCP_DRAIN);
337 	for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next)
338 		tcp_drainunack(intotcpcb(ip));
339 }
340 
341 tcp_drainunack(tp)
342 	register struct tcpcb *tp;
343 {
344 	register struct mbuf *m;
345 
346 COUNT(TCP_DRAINUNACK);
347 	for (m = tp->seg_unack; m; m = m->m_act)
348 		m_freem(m);
349 	tp->seg_unack = 0;
350 }
351 
352 tcp_ctlinput(m)
353 	struct mbuf *m;
354 {
355 
356 COUNT(TCP_CTLINPUT);
357 	m_freem(m);
358 }
359