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