xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 5276)
1 /* tcp_usrreq.c 1.44 81/12/20 */
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/in.h"
10 #include "../net/in_pcb.h"
11 #include "../net/in_systm.h"
12 #include "../net/if.h"
13 #include "../net/ip.h"
14 #include "../net/ip_var.h"
15 #include "../net/tcp.h"
16 #include "../net/tcp_fsm.h"
17 #include "../net/tcp_seq.h"
18 #include "../net/tcp_timer.h"
19 #include "../net/tcp_var.h"
20 #include "../net/tcpip.h"
21 #include "../net/tcp_debug.h"
22 #include "../errno.h"
23 
24 extern char *tcpstates[];
25 struct	tcpcb *tcp_newtcpcb();
26 /*
27  * Process a TCP user request for tcp tb.  If this is a send request
28  * then m is the mbuf chain of send data.  If this is a timer expiration
29  * (called from the software clock routine), then timertype tells which timer.
30  */
31 tcp_usrreq(so, req, m, addr)
32 	struct socket *so;
33 	int req;
34 	struct mbuf *m;
35 	caddr_t addr;
36 {
37 	register struct inpcb *inp = sotoinpcb(so);
38 	register struct tcpcb *tp;
39 	int s = splnet();
40 	int error = 0;
41 	int ostate;
42 COUNT(TCP_USRREQ);
43 
44 	/*
45 	 * Make sure attached.  If not,
46 	 * only PRU_ATTACH is valid.
47 	 */
48 	if (inp == 0 && req != PRU_ATTACH) {
49 		splx(s);
50 		return (EINVAL);
51 	}
52 	if (inp) {
53 		tp = intotcpcb(inp);
54 #ifdef KPROF
55 		tcp_acounts[tp->t_state][req]++;
56 #endif
57 		ostate = tp->t_state;
58 	}
59 	switch (req) {
60 
61 	case PRU_ATTACH:
62 		if (inp) {
63 			error = EISCONN;
64 			break;
65 		}
66 		error = in_pcbattach(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
67 		if (error)
68 			break;
69 		inp = (struct inpcb *)so->so_pcb;
70 		tp = tcp_newtcpcb(inp);
71 		if (so->so_options & SO_ACCEPTCONN) {
72 			if (tp == 0) {
73 				in_pcbdetach(inp);
74 				error = ENOBUFS;
75 				break;
76 			}
77 			tp->t_state = TCPS_LISTEN;
78 		} else
79 			tp->t_state = TCPS_CLOSED;
80 		break;
81 
82 	case PRU_DETACH:
83 		if (tp)
84 			goto disconn;
85 		in_pcbdetach(inp);
86 		break;
87 
88 	case PRU_CONNECT:
89 		error = in_pcbconnect(inp, (struct sockaddr_in *)addr);
90 		if (error)
91 			break;
92 		tp->t_template = tcp_template(tp);
93 		if (tp->t_template == 0)
94 			goto badcon2;
95 		tp->t_inpcb = inp;
96 		inp->inp_ppcb = (caddr_t)tp;
97 		soisconnecting(so);
98 		tp->t_state = TCPS_SYN_SENT;
99 		tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
100 		tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
101 		tcp_sendseqinit(tp);
102 		(void) tcp_output(tp);
103 		break;
104 
105 badcon2:
106 		(void) m_free(dtom(tp));
107 badcon:
108 		in_pcbdisconnect(inp);
109 		error = ENOBUFS;
110 		break;
111 
112 	case PRU_ACCEPT:
113 		*(struct sockaddr *)addr = so->so_addr;
114 		break;
115 
116 	case PRU_DISCONNECT:
117 disconn:
118 		if (tp->t_state < TCPS_ESTABLISHED)
119 			tcp_close(tp);
120 		else if ((so->so_state & SO_LETDATADRAIN) == 0)
121 			tcp_drop(tp, 0);
122 		else {
123 			soisdisconnecting(so);
124 			sbflush(&so->so_rcv);
125 			tcp_usrclosed(tp);
126 			(void) tcp_output(tp);
127 		}
128 		break;
129 
130 	case PRU_SHUTDOWN:
131 		socantsendmore(so);
132 		tcp_usrclosed(tp);
133 		(void) tcp_output(tp);
134 		break;
135 
136 	case PRU_RCVD:
137 		(void) tcp_output(tp);
138 		break;
139 
140 	case PRU_SEND:
141 		sbappend(&so->so_snd, m);
142 /*
143 		if (tp->t_flags & TF_PUSH)
144 			tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
145  */
146 		if (tp->t_flags & TF_URG)
147 			tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1;
148 		(void) tcp_output(tp);
149 		break;
150 
151 	case PRU_ABORT:
152 		tcp_drop(tp, ECONNABORTED);
153 		break;
154 
155 	case PRU_CONTROL:
156 		error = EOPNOTSUPP;
157 		break;
158 
159 	case PRU_SENSE:
160 		error = EOPNOTSUPP;
161 		break;
162 
163 	case PRU_RCVOOB:
164 		error = EOPNOTSUPP;
165 		break;
166 
167 	case PRU_SENDOOB:
168 		error = EOPNOTSUPP;
169 		break;
170 
171 	case PRU_SLOWTIMO:
172 		tcp_timers(tp, (int)addr);
173 		req |= (int)addr << 8;		/* for debug's sake */
174 		break;
175 
176 	default:
177 		panic("tcp_usrreq");
178 	}
179 	if (tp && (so->so_options & SO_DEBUG))
180 		tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
181 	splx(s);
182 	return (error);
183 }
184 
185 tcp_usrclosed(tp)
186 	struct tcpcb *tp;
187 {
188 
189 	switch (tp->t_state) {
190 
191 	case TCPS_LISTEN:
192 	case TCPS_SYN_SENT:
193 		tp->t_state = TCPS_CLOSED;
194 		tcp_close(tp);
195 		break;
196 
197 	case TCPS_SYN_RECEIVED:
198 	case TCPS_ESTABLISHED:
199 		tp->t_state = TCPS_FIN_WAIT_1;
200 		break;
201 
202 	case TCPS_CLOSE_WAIT:
203 		tp->t_state = TCPS_LAST_ACK;
204 		break;
205 	}
206 }
207