|
|
1.1 root 1: /* tcp_usrreq.c 6.1 83/07/29 */
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 "../h/errno.h"
10:
11: #include "../net/if.h"
12: #include "../net/route.h"
13:
14: #include "../netinet/in.h"
15: #include "../netinet/in_pcb.h"
16: #include "../netinet/in_systm.h"
17: #include "../netinet/ip.h"
18: #include "../netinet/ip_var.h"
19: #include "../netinet/tcp.h"
20: #include "../netinet/tcp_fsm.h"
21: #include "../netinet/tcp_seq.h"
22: #include "../netinet/tcp_timer.h"
23: #include "../netinet/tcp_var.h"
24: #include "../netinet/tcpip.h"
25: #include "../netinet/tcp_debug.h"
26:
27: /*
28: * TCP protocol interface to socket abstraction.
29: */
30: extern char *tcpstates[];
31: struct tcpcb *tcp_newtcpcb();
32: int tcpsenderrors;
33:
34: /*
35: * Process a TCP user request for TCP tb. If this is a send request
36: * then m is the mbuf chain of send data. If this is a timer expiration
37: * (called from the software clock routine), then timertype tells which timer.
38: */
39: /*ARGSUSED*/
40: tcp_usrreq(so, req, m, nam, rights)
41: struct socket *so;
42: int req;
43: struct mbuf *m, *nam, *rights;
44: {
45: register struct inpcb *inp = sotoinpcb(so);
46: register struct tcpcb *tp;
47: int s = splnet();
48: int error = 0;
49: int ostate;
50:
51: if (rights && rights->m_len) {
52: splx(s);
53: return (EINVAL);
54: }
55: /*
56: * When a TCP is attached to a socket, then there will be
57: * a (struct inpcb) pointed at by the socket, and this
58: * structure will point at a subsidary (struct tcpcb).
59: */
60: if (inp == 0 && req != PRU_ATTACH) {
61: splx(s);
62: return (EINVAL); /* XXX */
63: }
64: if (inp) {
65: tp = intotcpcb(inp);
66: /* WHAT IF TP IS 0? */
67: #ifdef KPROF
68: tcp_acounts[tp->t_state][req]++;
69: #endif
70: ostate = tp->t_state;
71: } else
72: ostate = 0;
73: switch (req) {
74:
75: /*
76: * TCP attaches to socket via PRU_ATTACH, reserving space,
77: * and an internet control block.
78: */
79: case PRU_ATTACH:
80: if (inp) {
81: error = EISCONN;
82: break;
83: }
84: error = tcp_attach(so);
85: if (error)
86: break;
87: if ((so->so_options & SO_LINGER) && so->so_linger == 0)
88: so->so_linger = TCP_LINGERTIME;
89: tp = sototcpcb(so);
90: break;
91:
92: /*
93: * PRU_DETACH detaches the TCP protocol from the socket.
94: * If the protocol state is non-embryonic, then can't
95: * do this directly: have to initiate a PRU_DISCONNECT,
96: * which may finish later; embryonic TCB's can just
97: * be discarded here.
98: */
99: case PRU_DETACH:
100: if (tp->t_state > TCPS_LISTEN)
101: tp = tcp_disconnect(tp);
102: else
103: tp = tcp_close(tp);
104: break;
105:
106: /*
107: * Give the socket an address.
108: */
109: case PRU_BIND:
110: error = in_pcbbind(inp, nam);
111: if (error)
112: break;
113: break;
114:
115: /*
116: * Prepare to accept connections.
117: */
118: case PRU_LISTEN:
119: if (inp->inp_lport == 0)
120: error = in_pcbbind(inp, (struct mbuf *)0);
121: if (error == 0)
122: tp->t_state = TCPS_LISTEN;
123: break;
124:
125: /*
126: * Initiate connection to peer.
127: * Create a template for use in transmissions on this connection.
128: * Enter SYN_SENT state, and mark socket as connecting.
129: * Start keep-alive timer, and seed output sequence space.
130: * Send initial segment on connection.
131: */
132: case PRU_CONNECT:
133: if (inp->inp_lport == 0) {
134: error = in_pcbbind(inp, (struct mbuf *)0);
135: if (error)
136: break;
137: }
138: error = in_pcbconnect(inp, nam);
139: if (error)
140: break;
141: tp->t_template = tcp_template(tp);
142: if (tp->t_template == 0) {
143: in_pcbdisconnect(inp);
144: error = ENOBUFS;
145: break;
146: }
147: soisconnecting(so);
148: tp->t_state = TCPS_SYN_SENT;
149: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP;
150: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
151: tcp_sendseqinit(tp);
152: error = tcp_output(tp);
153: break;
154:
155: /*
156: * Create a TCP connection between two sockets.
157: */
158: case PRU_CONNECT2:
159: error = EOPNOTSUPP;
160: break;
161:
162: /*
163: * Initiate disconnect from peer.
164: * If connection never passed embryonic stage, just drop;
165: * else if don't need to let data drain, then can just drop anyways,
166: * else have to begin TCP shutdown process: mark socket disconnecting,
167: * drain unread data, state switch to reflect user close, and
168: * send segment (e.g. FIN) to peer. Socket will be really disconnected
169: * when peer sends FIN and acks ours.
170: *
171: * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
172: */
173: case PRU_DISCONNECT:
174: tp = tcp_disconnect(tp);
175: break;
176:
177: /*
178: * Accept a connection. Essentially all the work is
179: * done at higher levels; just return the address
180: * of the peer, storing through addr.
181: */
182: case PRU_ACCEPT: {
183: struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
184:
185: nam->m_len = sizeof (struct sockaddr_in);
186: sin->sin_family = AF_INET;
187: sin->sin_port = inp->inp_fport;
188: sin->sin_addr = inp->inp_faddr;
189: break;
190: }
191:
192: /*
193: * Mark the connection as being incapable of further output.
194: */
195: case PRU_SHUTDOWN:
196: socantsendmore(so);
197: tp = tcp_usrclosed(tp);
198: if (tp)
199: error = tcp_output(tp);
200: break;
201:
202: /*
203: * After a receive, possibly send window update to peer.
204: */
205: case PRU_RCVD:
206: (void) tcp_output(tp);
207: break;
208:
209: /*
210: * Do a send by putting data in output queue and updating urgent
211: * marker if URG set. Possibly send more data.
212: */
213: case PRU_SEND:
214: sbappend(&so->so_snd, m);
215: #ifdef notdef
216: if (tp->t_flags & TF_PUSH)
217: tp->snd_end = tp->snd_una + so->so_snd.sb_cc;
218: #endif
219: error = tcp_output(tp);
220: if (error) { /* XXX fix to use other path */
221: if (error == ENOBUFS) /* XXX */
222: error = 0; /* XXX */
223: tcpsenderrors++;
224: }
225: break;
226:
227: /*
228: * Abort the TCP.
229: */
230: case PRU_ABORT:
231: tp = tcp_drop(tp, ECONNABORTED);
232: break;
233:
234: /* SOME AS YET UNIMPLEMENTED HOOKS */
235: case PRU_CONTROL:
236: error = EOPNOTSUPP;
237: break;
238:
239: case PRU_SENSE:
240: error = EOPNOTSUPP;
241: break;
242: /* END UNIMPLEMENTED HOOKS */
243:
244: case PRU_RCVOOB:
245: if (so->so_oobmark == 0 &&
246: (so->so_state & SS_RCVATMARK) == 0) {
247: error = EINVAL;
248: break;
249: }
250: if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
251: error = EWOULDBLOCK;
252: break;
253: }
254: m->m_len = 1;
255: *mtod(m, caddr_t) = tp->t_iobc;
256: break;
257:
258: case PRU_SENDOOB:
259: if (sbspace(&so->so_snd) < -512) {
260: m_freem(m);
261: error = ENOBUFS;
262: break;
263: }
264: tp->snd_up = tp->snd_una + so->so_snd.sb_cc + 1;
265: sbappend(&so->so_snd, m);
266: tp->t_force = 1;
267: error = tcp_output(tp);
268: tp->t_force = 0;
269: break;
270:
271: case PRU_SOCKADDR:
272: in_setsockaddr(inp, nam);
273: break;
274:
275: case PRU_PEERADDR:
276: in_setpeeraddr(inp, nam);
277: break;
278:
279: /*
280: * TCP slow timer went off; going through this
281: * routine for tracing's sake.
282: */
283: case PRU_SLOWTIMO:
284: tp = tcp_timers(tp, (int)nam);
285: req |= (int)nam << 8; /* for debug's sake */
286: break;
287:
288: default:
289: panic("tcp_usrreq");
290: }
291: if (tp && (so->so_options & SO_DEBUG))
292: tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
293: splx(s);
294: return (error);
295: }
296:
297: int tcp_sendspace = 1024*2;
298: int tcp_recvspace = 1024*2;
299: /*
300: * Attach TCP protocol to socket, allocating
301: * internet protocol control block, tcp control block,
302: * bufer space, and entering LISTEN state if to accept connections.
303: */
304: tcp_attach(so)
305: struct socket *so;
306: {
307: register struct tcpcb *tp;
308: struct inpcb *inp;
309: int error;
310:
311: error = soreserve(so, tcp_sendspace, tcp_recvspace);
312: if (error)
313: goto bad;
314: error = in_pcballoc(so, &tcb);
315: if (error)
316: goto bad;
317: inp = sotoinpcb(so);
318: tp = tcp_newtcpcb(inp);
319: if (tp == 0) {
320: error = ENOBUFS;
321: goto bad2;
322: }
323: tp->t_state = TCPS_CLOSED;
324: return (0);
325: bad2:
326: in_pcbdetach(inp);
327: bad:
328: return (error);
329: }
330:
331: /*
332: * Initiate (or continue) disconnect.
333: * If embryonic state, just send reset (once).
334: * If in ``let data drain'' option and linger null, just drop.
335: * Otherwise (hard), mark socket disconnecting and drop
336: * current input data; switch states based on user close, and
337: * send segment to peer (with FIN).
338: */
339: struct tcpcb *
340: tcp_disconnect(tp)
341: register struct tcpcb *tp;
342: {
343: struct socket *so = tp->t_inpcb->inp_socket;
344:
345: if (tp->t_state < TCPS_ESTABLISHED)
346: tp = tcp_close(tp);
347: else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
348: tp = tcp_drop(tp, 0);
349: else {
350: soisdisconnecting(so);
351: sbflush(&so->so_rcv);
352: tp = tcp_usrclosed(tp);
353: if (tp)
354: (void) tcp_output(tp);
355: }
356: return (tp);
357: }
358:
359: /*
360: * User issued close, and wish to trail through shutdown states:
361: * if never received SYN, just forget it. If got a SYN from peer,
362: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
363: * If already got a FIN from peer, then almost done; go to LAST_ACK
364: * state. In all other cases, have already sent FIN to peer (e.g.
365: * after PRU_SHUTDOWN), and just have to play tedious game waiting
366: * for peer to send FIN or not respond to keep-alives, etc.
367: * We can let the user exit from the close as soon as the FIN is acked.
368: */
369: struct tcpcb *
370: tcp_usrclosed(tp)
371: register struct tcpcb *tp;
372: {
373:
374: switch (tp->t_state) {
375:
376: case TCPS_CLOSED:
377: case TCPS_LISTEN:
378: case TCPS_SYN_SENT:
379: tp->t_state = TCPS_CLOSED;
380: tp = tcp_close(tp);
381: break;
382:
383: case TCPS_SYN_RECEIVED:
384: case TCPS_ESTABLISHED:
385: tp->t_state = TCPS_FIN_WAIT_1;
386: break;
387:
388: case TCPS_CLOSE_WAIT:
389: tp->t_state = TCPS_LAST_ACK;
390: break;
391: }
392: if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
393: soisdisconnected(tp->t_inpcb->inp_socket);
394: return (tp);
395: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.