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