Commit | Line | Data |
---|---|---|
1067fd0f | 1 | /* |
6a479bcf | 2 | * Copyright (c) 1992 Regents of the University of California. |
1067fd0f KS |
3 | * All rights reserved. |
4 | * | |
5 | * %sccs.include.redist.c% | |
6 | * | |
00fe43e0 | 7 | * @(#)tuba_usrreq.c 7.9 (Berkeley) %G% |
1067fd0f KS |
8 | */ |
9 | ||
21715d8e KS |
10 | #include <sys/param.h> |
11 | #include <sys/systm.h> | |
12 | #include <sys/malloc.h> | |
13 | #include <sys/mbuf.h> | |
14 | #include <sys/socket.h> | |
15 | #include <sys/socketvar.h> | |
16 | #include <sys/protosw.h> | |
17 | #include <sys/errno.h> | |
18 | #include <sys/stat.h> | |
1067fd0f | 19 | |
21715d8e KS |
20 | #include <net/if.h> |
21 | #include <net/route.h> | |
1067fd0f | 22 | |
21715d8e KS |
23 | #include <netinet/in.h> |
24 | #include <netinet/in_systm.h> | |
25 | #include <netinet/ip.h> | |
26 | #include <netinet/in_pcb.h> | |
27 | #include <netinet/ip_var.h> | |
28 | #include <netinet/tcp.h> | |
29 | #include <netinet/tcp_fsm.h> | |
30 | #include <netinet/tcp_seq.h> | |
31 | #include <netinet/tcp_timer.h> | |
32 | #include <netinet/tcp_var.h> | |
33 | #include <netinet/tcpip.h> | |
34 | #include <netinet/tcp_debug.h> | |
1067fd0f | 35 | |
21715d8e KS |
36 | #include <netiso/argo_debug.h> |
37 | #include <netiso/iso.h> | |
38 | #include <netiso/clnp.h> | |
39 | #include <netiso/iso_pcb.h> | |
40 | #include <netiso/iso_var.h> | |
77db2796 | 41 | #include <netiso/tuba_table.h> |
1067fd0f KS |
42 | /* |
43 | * TCP protocol interface to socket abstraction. | |
44 | */ | |
45 | extern char *tcpstates[]; | |
98a71798 KS |
46 | extern struct inpcb tuba_inpcb; |
47 | extern struct isopcb tuba_isopcb; | |
1067fd0f KS |
48 | |
49 | /* | |
50 | * Process a TCP user request for TCP tb. If this is a send request | |
51 | * then m is the mbuf chain of send data. If this is a timer expiration | |
52 | * (called from the software clock routine), then timertype tells which timer. | |
53 | */ | |
54 | /*ARGSUSED*/ | |
55 | tuba_usrreq(so, req, m, nam, control) | |
56 | struct socket *so; | |
57 | int req; | |
58 | struct mbuf *m, *nam, *control; | |
59 | { | |
60 | register struct inpcb *inp; | |
61 | register struct isopcb *isop; | |
62 | register struct tcpcb *tp; | |
63 | int s; | |
64 | int error = 0; | |
65 | int ostate; | |
21715d8e | 66 | struct sockaddr_iso *siso; |
1067fd0f KS |
67 | |
68 | if (req == PRU_CONTROL) | |
69 | return (iso_control(so, (int)m, (caddr_t)nam, | |
70 | (struct ifnet *)control)); | |
71 | ||
72 | s = splnet(); | |
73 | inp = sotoinpcb(so); | |
74 | /* | |
75 | * When a TCP is attached to a socket, then there will be | |
76 | * a (struct inpcb) pointed at by the socket, and this | |
77 | * structure will point at a subsidary (struct tcpcb). | |
78 | */ | |
79 | if (inp == 0 && req != PRU_ATTACH) { | |
80 | splx(s); | |
81 | return (EINVAL); /* XXX */ | |
82 | } | |
83 | if (inp) { | |
21715d8e | 84 | tp = intotcpcb(inp); |
1067fd0f KS |
85 | if (tp == 0) |
86 | panic("tuba_usrreq"); | |
87 | ostate = tp->t_state; | |
21715d8e | 88 | isop = (struct isopcb *)tp->t_tuba_pcb; |
1067fd0f KS |
89 | if (isop == 0) |
90 | panic("tuba_usrreq 2"); | |
91 | } else | |
92 | ostate = 0; | |
93 | switch (req) { | |
94 | ||
95 | /* | |
96 | * TCP attaches to socket via PRU_ATTACH, reserving space, | |
97 | * and an internet control block. We also need to | |
98 | * allocate an isopcb and separate the control block from | |
99 | * tcp/ip ones. | |
100 | */ | |
101 | case PRU_ATTACH: | |
102 | if (error = iso_pcballoc(so, &tuba_isopcb)) | |
103 | break; | |
77db2796 KS |
104 | isop = (struct isopcb *)so->so_pcb; |
105 | so->so_pcb = 0; | |
106 | if (error = tcp_usrreq(so, req, m, nam, control)) { | |
1067fd0f | 107 | isop->isop_socket = 0; |
77db2796 KS |
108 | iso_pcbdetach(isop); |
109 | } else { | |
110 | inp = sotoinpcb(so); | |
98a71798 KS |
111 | remque(inp); |
112 | insque(inp, &tuba_inpcb); | |
113 | inp->inp_head = &tuba_inpcb; | |
77db2796 KS |
114 | tp = intotcpcb(inp); |
115 | if (tp == 0) | |
116 | panic("tuba_usrreq 3"); | |
117 | tp->t_tuba_pcb = (caddr_t) isop; | |
1067fd0f KS |
118 | } |
119 | goto notrace; | |
120 | ||
121 | /* | |
122 | * PRU_DETACH detaches the TCP protocol from the socket. | |
123 | * If the protocol state is non-embryonic, then can't | |
124 | * do this directly: have to initiate a PRU_DISCONNECT, | |
125 | * which may finish later; embryonic TCB's can just | |
126 | * be discarded here. | |
127 | */ | |
128 | case PRU_DETACH: | |
129 | if (tp->t_state > TCPS_LISTEN) | |
130 | tp = tcp_disconnect(tp); | |
131 | else | |
132 | tp = tcp_close(tp); | |
133 | if (tp == 0) | |
134 | tuba_pcbdetach(isop); | |
135 | break; | |
136 | ||
137 | /* | |
138 | * Give the socket an address. | |
139 | */ | |
140 | case PRU_BIND: | |
141 | siso = mtod(nam, struct sockaddr_iso *); | |
142 | if (siso->siso_tlen && siso->siso_tlen != 2) { | |
143 | error = EINVAL; | |
144 | break; | |
145 | } | |
146 | if ((error = iso_pcbbind(isop, nam)) || | |
147 | (siso = isop->isop_laddr) == 0) | |
148 | break; | |
149 | bcopy(TSEL(siso), &inp->inp_lport, 2); | |
150 | if (siso->siso_nlen && | |
7cfe65b5 | 151 | !(inp->inp_laddr.s_addr = tuba_lookup(siso, M_WAITOK))) |
1067fd0f KS |
152 | error = ENOBUFS; |
153 | break; | |
154 | ||
155 | /* | |
156 | * Prepare to accept connections. | |
157 | */ | |
158 | case PRU_CONNECT: | |
159 | case PRU_LISTEN: | |
160 | if (inp->inp_lport == 0 && | |
161 | (error = iso_pcbbind(isop, (struct mbuf *)0))) | |
162 | break; | |
163 | bcopy(TSEL(isop->isop_laddr), &inp->inp_lport, 2); | |
21715d8e | 164 | if (req == PRU_LISTEN) { |
1067fd0f KS |
165 | tp->t_state = TCPS_LISTEN; |
166 | break; | |
167 | } | |
168 | /*FALLTHROUGH*/ | |
169 | /* | |
170 | * Initiate connection to peer. | |
171 | * Create a template for use in transmissions on this connection. | |
172 | * Enter SYN_SENT state, and mark socket as connecting. | |
173 | * Start keep-alive timer, and seed output sequence space. | |
174 | * Send initial segment on connection. | |
175 | */ | |
176 | /* case PRU_CONNECT: */ | |
177 | if (error = iso_pcbconnect(isop, nam)) | |
178 | break; | |
315cfecc KS |
179 | if ((siso = isop->isop_laddr) && siso->siso_nlen > 1) |
180 | siso->siso_data[siso->siso_nlen - 1] = ISOPROTO_TCP; | |
181 | else | |
182 | panic("tuba_usrreq: connect"); | |
1067fd0f | 183 | siso = mtod(nam, struct sockaddr_iso *); |
7cfe65b5 | 184 | if (!(inp->inp_faddr.s_addr = tuba_lookup(siso, M_WAITOK))) { |
1067fd0f KS |
185 | unconnect: |
186 | iso_pcbdisconnect(isop); | |
187 | error = ENOBUFS; | |
188 | break; | |
189 | } | |
190 | bcopy(TSEL(isop->isop_faddr), &inp->inp_fport, 2); | |
21715d8e | 191 | if (inp->inp_laddr.s_addr == 0 && |
1067fd0f | 192 | (inp->inp_laddr.s_addr = |
7cfe65b5 | 193 | tuba_lookup(isop->isop_laddr, M_WAITOK)) == 0) |
1067fd0f KS |
194 | goto unconnect; |
195 | if ((tp->t_template = tcp_template(tp)) == 0) | |
196 | goto unconnect; | |
197 | soisconnecting(so); | |
198 | tcpstat.tcps_connattempt++; | |
199 | tp->t_state = TCPS_SYN_SENT; | |
200 | tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; | |
201 | tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2; | |
202 | tcp_sendseqinit(tp); | |
203 | error = tcp_output(tp); | |
204 | tuba_refcnt(isop, 1); | |
205 | break; | |
206 | ||
207 | /* | |
208 | * Initiate disconnect from peer. | |
209 | * If connection never passed embryonic stage, just drop; | |
210 | * else if don't need to let data drain, then can just drop anyways, | |
211 | * else have to begin TCP shutdown process: mark socket disconnecting, | |
212 | * drain unread data, state switch to reflect user close, and | |
213 | * send segment (e.g. FIN) to peer. Socket will be really disconnected | |
214 | * when peer sends FIN and acks ours. | |
215 | * | |
216 | * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB. | |
217 | */ | |
218 | case PRU_DISCONNECT: | |
219 | if ((tp = tcp_disconnect(tp)) == 0) | |
220 | tuba_pcbdetach(isop); | |
221 | break; | |
222 | ||
223 | /* | |
224 | * Accept a connection. Essentially all the work is | |
225 | * done at higher levels; just return the address | |
226 | * of the peer, storing through addr. | |
227 | */ | |
228 | case PRU_ACCEPT: | |
ff38aee7 | 229 | bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), |
1067fd0f KS |
230 | nam->m_len = isop->isop_faddr->siso_len); |
231 | break; | |
232 | ||
233 | /* | |
234 | * Mark the connection as being incapable of further output. | |
235 | */ | |
236 | case PRU_SHUTDOWN: | |
237 | socantsendmore(so); | |
238 | tp = tcp_usrclosed(tp); | |
239 | if (tp) | |
240 | error = tcp_output(tp); | |
241 | else | |
242 | tuba_pcbdetach(isop); | |
243 | break; | |
244 | /* | |
245 | * Abort the TCP. | |
246 | */ | |
247 | case PRU_ABORT: | |
248 | if ((tp = tcp_drop(tp, ECONNABORTED)) == 0) | |
249 | tuba_pcbdetach(isop); | |
250 | break; | |
251 | ||
252 | ||
253 | case PRU_SOCKADDR: | |
254 | if (isop->isop_laddr) | |
00fe43e0 | 255 | bcopy((caddr_t)isop->isop_laddr, mtod(nam, caddr_t), |
1067fd0f KS |
256 | nam->m_len = isop->isop_laddr->siso_len); |
257 | break; | |
258 | ||
259 | case PRU_PEERADDR: | |
260 | if (isop->isop_faddr) | |
00fe43e0 | 261 | bcopy((caddr_t)isop->isop_faddr, mtod(nam, caddr_t), |
1067fd0f KS |
262 | nam->m_len = isop->isop_faddr->siso_len); |
263 | break; | |
264 | ||
265 | default: | |
266 | error = tcp_usrreq(so, req, m, nam, control); | |
267 | goto notrace; | |
268 | } | |
269 | if (tp && (so->so_options & SO_DEBUG)) | |
270 | tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req); | |
271 | notrace: | |
272 | splx(s); | |
273 | return(error); | |
274 | } | |
275 | ||
276 | tuba_ctloutput(op, so, level, optname, mp) | |
277 | int op; | |
278 | struct socket *so; | |
279 | int level, optname; | |
280 | struct mbuf **mp; | |
281 | { | |
282 | int clnp_ctloutput(), tcp_ctloutput(); | |
283 | ||
284 | return ((level != IPPROTO_TCP ? clnp_ctloutput : tcp_ctloutput) | |
7cfe65b5 | 285 | (op, so, level, optname, mp)); |
1067fd0f | 286 | } |