|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)tcp_usrreq.c 7.15 (Berkeley) 6/28/90
34: */
35:
36: #include "param.h"
37: #include "systm.h"
38: #include "malloc.h"
39: #include "mbuf.h"
40: #include "socket.h"
41: #include "socketvar.h"
42: #include "protosw.h"
43: #include "errno.h"
44: #include "stat.h"
45:
46: #include "../net/if.h"
47: #include "../net/route.h"
48:
49: #include "in.h"
50: #include "in_systm.h"
51: #include "ip.h"
52: #include "in_pcb.h"
53: #include "ip_var.h"
54: #include "tcp.h"
55: #include "tcp_fsm.h"
56: #include "tcp_seq.h"
57: #include "tcp_timer.h"
58: #include "tcp_var.h"
59: #include "tcpip.h"
60: #include "tcp_debug.h"
61:
62: /*
63: * TCP protocol interface to socket abstraction.
64: */
65: extern char *tcpstates[];
66: struct tcpcb *tcp_newtcpcb();
67:
68: /*
69: * Process a TCP user request for TCP tb. If this is a send request
70: * then m is the mbuf chain of send data. If this is a timer expiration
71: * (called from the software clock routine), then timertype tells which timer.
72: */
73: /*ARGSUSED*/
74: tcp_usrreq(so, req, m, nam, control)
75: struct socket *so;
76: int req;
77: struct mbuf *m, *nam, *control;
78: {
79: register struct inpcb *inp;
80: register struct tcpcb *tp;
81: int s;
82: int error = 0;
83: int ostate;
84:
85: if (req == PRU_CONTROL)
86: return (in_control(so, (int)m, (caddr_t)nam,
87: (struct ifnet *)control));
88: if (control && control->m_len) {
89: m_freem(control);
90: if (m)
91: m_freem(m);
92: return (EINVAL);
93: }
94:
95: s = splnet();
96: inp = sotoinpcb(so);
97: /*
98: * When a TCP is attached to a socket, then there will be
99: * a (struct inpcb) pointed at by the socket, and this
100: * structure will point at a subsidary (struct tcpcb).
101: */
102: if (inp == 0 && req != PRU_ATTACH) {
103: splx(s);
104: return (EINVAL); /* XXX */
105: }
106: if (inp) {
107: tp = intotcpcb(inp);
108: /* WHAT IF TP IS 0? */
109: #ifdef KPROF
110: tcp_acounts[tp->t_state][req]++;
111: #endif
112: ostate = tp->t_state;
113: } else
114: ostate = 0;
115: switch (req) {
116:
117: /*
118: * TCP attaches to socket via PRU_ATTACH, reserving space,
119: * and an internet control block.
120: */
121: case PRU_ATTACH:
122: if (inp) {
123: error = EISCONN;
124: break;
125: }
126: error = tcp_attach(so);
127: if (error)
128: break;
129: if ((so->so_options & SO_LINGER) && so->so_linger == 0)
130: so->so_linger = TCP_LINGERTIME;
131: tp = sototcpcb(so);
132: break;
133:
134: /*
135: * PRU_DETACH detaches the TCP protocol from the socket.
136: * If the protocol state is non-embryonic, then can't
137: * do this directly: have to initiate a PRU_DISCONNECT,
138: * which may finish later; embryonic TCB's can just
139: * be discarded here.
140: */
141: case PRU_DETACH:
142: if (tp->t_state > TCPS_LISTEN)
143: tp = tcp_disconnect(tp);
144: else
145: tp = tcp_close(tp);
146: break;
147:
148: /*
149: * Give the socket an address.
150: */
151: case PRU_BIND:
152: error = in_pcbbind(inp, nam);
153: if (error)
154: break;
155: break;
156:
157: /*
158: * Prepare to accept connections.
159: */
160: case PRU_LISTEN:
161: if (inp->inp_lport == 0)
162: error = in_pcbbind(inp, (struct mbuf *)0);
163: if (error == 0)
164: tp->t_state = TCPS_LISTEN;
165: break;
166:
167: /*
168: * Initiate connection to peer.
169: * Create a template for use in transmissions on this connection.
170: * Enter SYN_SENT state, and mark socket as connecting.
171: * Start keep-alive timer, and seed output sequence space.
172: * Send initial segment on connection.
173: */
174: case PRU_CONNECT:
175: if (inp->inp_lport == 0) {
176: error = in_pcbbind(inp, (struct mbuf *)0);
177: if (error)
178: break;
179: }
180: error = in_pcbconnect(inp, nam);
181: if (error)
182: break;
183: tp->t_template = tcp_template(tp);
184: if (tp->t_template == 0) {
185: in_pcbdisconnect(inp);
186: error = ENOBUFS;
187: break;
188: }
189: soisconnecting(so);
190: tcpstat.tcps_connattempt++;
191: tp->t_state = TCPS_SYN_SENT;
192: tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
193: tp->iss = tcp_iss; tcp_iss += TCP_ISSINCR/2;
194: tcp_sendseqinit(tp);
195: error = tcp_output(tp);
196: break;
197:
198: /*
199: * Create a TCP connection between two sockets.
200: */
201: case PRU_CONNECT2:
202: error = EOPNOTSUPP;
203: break;
204:
205: /*
206: * Initiate disconnect from peer.
207: * If connection never passed embryonic stage, just drop;
208: * else if don't need to let data drain, then can just drop anyways,
209: * else have to begin TCP shutdown process: mark socket disconnecting,
210: * drain unread data, state switch to reflect user close, and
211: * send segment (e.g. FIN) to peer. Socket will be really disconnected
212: * when peer sends FIN and acks ours.
213: *
214: * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
215: */
216: case PRU_DISCONNECT:
217: tp = tcp_disconnect(tp);
218: break;
219:
220: /*
221: * Accept a connection. Essentially all the work is
222: * done at higher levels; just return the address
223: * of the peer, storing through addr.
224: */
225: case PRU_ACCEPT: {
226: struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
227:
228: nam->m_len = sizeof (struct sockaddr_in);
229: sin->sin_family = AF_INET;
230: sin->sin_len = sizeof(*sin);
231: sin->sin_port = inp->inp_fport;
232: sin->sin_addr = inp->inp_faddr;
233: break;
234: }
235:
236: /*
237: * Mark the connection as being incapable of further output.
238: */
239: case PRU_SHUTDOWN:
240: socantsendmore(so);
241: tp = tcp_usrclosed(tp);
242: if (tp)
243: error = tcp_output(tp);
244: break;
245:
246: /*
247: * After a receive, possibly send window update to peer.
248: */
249: case PRU_RCVD:
250: (void) tcp_output(tp);
251: break;
252:
253: /*
254: * Do a send by putting data in output queue and updating urgent
255: * marker if URG set. Possibly send more data.
256: */
257: case PRU_SEND:
258: sbappend(&so->so_snd, m);
259: error = tcp_output(tp);
260: break;
261:
262: /*
263: * Abort the TCP.
264: */
265: case PRU_ABORT:
266: tp = tcp_drop(tp, ECONNABORTED);
267: break;
268:
269: case PRU_SENSE:
270: ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
271: (void) splx(s);
272: return (0);
273:
274: case PRU_RCVOOB:
275: if ((so->so_oobmark == 0 &&
276: (so->so_state & SS_RCVATMARK) == 0) ||
277: so->so_options & SO_OOBINLINE ||
278: tp->t_oobflags & TCPOOB_HADDATA) {
279: error = EINVAL;
280: break;
281: }
282: if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
283: error = EWOULDBLOCK;
284: break;
285: }
286: m->m_len = 1;
287: *mtod(m, caddr_t) = tp->t_iobc;
288: if (((int)nam & MSG_PEEK) == 0)
289: tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
290: break;
291:
292: case PRU_SENDOOB:
293: if (sbspace(&so->so_snd) < -512) {
294: m_freem(m);
295: error = ENOBUFS;
296: break;
297: }
298: /*
299: * According to RFC961 (Assigned Protocols),
300: * the urgent pointer points to the last octet
301: * of urgent data. We continue, however,
302: * to consider it to indicate the first octet
303: * of data past the urgent section.
304: * Otherwise, snd_up should be one lower.
305: */
306: sbappend(&so->so_snd, m);
307: tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
308: tp->t_force = 1;
309: error = tcp_output(tp);
310: tp->t_force = 0;
311: break;
312:
313: case PRU_SOCKADDR:
314: in_setsockaddr(inp, nam);
315: break;
316:
317: case PRU_PEERADDR:
318: in_setpeeraddr(inp, nam);
319: break;
320:
321: /*
322: * TCP slow timer went off; going through this
323: * routine for tracing's sake.
324: */
325: case PRU_SLOWTIMO:
326: tp = tcp_timers(tp, (int)nam);
327: req |= (int)nam << 8; /* for debug's sake */
328: break;
329:
330: default:
331: panic("tcp_usrreq");
332: }
333: if (tp && (so->so_options & SO_DEBUG))
334: tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, req);
335: splx(s);
336: return (error);
337: }
338:
339: tcp_ctloutput(op, so, level, optname, mp)
340: int op;
341: struct socket *so;
342: int level, optname;
343: struct mbuf **mp;
344: {
345: int error = 0;
346: struct inpcb *inp = sotoinpcb(so);
347: register struct tcpcb *tp = intotcpcb(inp);
348: register struct mbuf *m;
349:
350: if (level != IPPROTO_TCP)
351: return (ip_ctloutput(op, so, level, optname, mp));
352:
353: switch (op) {
354:
355: case PRCO_SETOPT:
356: m = *mp;
357: switch (optname) {
358:
359: case TCP_NODELAY:
360: if (m == NULL || m->m_len < sizeof (int))
361: error = EINVAL;
362: else if (*mtod(m, int *))
363: tp->t_flags |= TF_NODELAY;
364: else
365: tp->t_flags &= ~TF_NODELAY;
366: break;
367:
368: case TCP_MAXSEG: /* not yet */
369: default:
370: error = EINVAL;
371: break;
372: }
373: if (m)
374: (void) m_free(m);
375: break;
376:
377: case PRCO_GETOPT:
378: *mp = m = m_get(M_WAIT, MT_SOOPTS);
379: m->m_len = sizeof(int);
380:
381: switch (optname) {
382: case TCP_NODELAY:
383: *mtod(m, int *) = tp->t_flags & TF_NODELAY;
384: break;
385: case TCP_MAXSEG:
386: *mtod(m, int *) = tp->t_maxseg;
387: break;
388: default:
389: error = EINVAL;
390: break;
391: }
392: break;
393: }
394: return (error);
395: }
396:
397: u_long tcp_sendspace = 1024*4;
398: u_long tcp_recvspace = 1024*4;
399:
400: /*
401: * Attach TCP protocol to socket, allocating
402: * internet protocol control block, tcp control block,
403: * bufer space, and entering LISTEN state if to accept connections.
404: */
405: tcp_attach(so)
406: struct socket *so;
407: {
408: register struct tcpcb *tp;
409: struct inpcb *inp;
410: int error;
411:
412: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
413: error = soreserve(so, tcp_sendspace, tcp_recvspace);
414: if (error)
415: return (error);
416: }
417: error = in_pcballoc(so, &tcb);
418: if (error)
419: return (error);
420: inp = sotoinpcb(so);
421: tp = tcp_newtcpcb(inp);
422: if (tp == 0) {
423: int nofd = so->so_state & SS_NOFDREF; /* XXX */
424:
425: so->so_state &= ~SS_NOFDREF; /* don't free the socket yet */
426: in_pcbdetach(inp);
427: so->so_state |= nofd;
428: return (ENOBUFS);
429: }
430: tp->t_state = TCPS_CLOSED;
431: return (0);
432: }
433:
434: /*
435: * Initiate (or continue) disconnect.
436: * If embryonic state, just send reset (once).
437: * If in ``let data drain'' option and linger null, just drop.
438: * Otherwise (hard), mark socket disconnecting and drop
439: * current input data; switch states based on user close, and
440: * send segment to peer (with FIN).
441: */
442: struct tcpcb *
443: tcp_disconnect(tp)
444: register struct tcpcb *tp;
445: {
446: struct socket *so = tp->t_inpcb->inp_socket;
447:
448: if (tp->t_state < TCPS_ESTABLISHED)
449: tp = tcp_close(tp);
450: else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
451: tp = tcp_drop(tp, 0);
452: else {
453: soisdisconnecting(so);
454: sbflush(&so->so_rcv);
455: tp = tcp_usrclosed(tp);
456: if (tp)
457: (void) tcp_output(tp);
458: }
459: return (tp);
460: }
461:
462: /*
463: * User issued close, and wish to trail through shutdown states:
464: * if never received SYN, just forget it. If got a SYN from peer,
465: * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
466: * If already got a FIN from peer, then almost done; go to LAST_ACK
467: * state. In all other cases, have already sent FIN to peer (e.g.
468: * after PRU_SHUTDOWN), and just have to play tedious game waiting
469: * for peer to send FIN or not respond to keep-alives, etc.
470: * We can let the user exit from the close as soon as the FIN is acked.
471: */
472: struct tcpcb *
473: tcp_usrclosed(tp)
474: register struct tcpcb *tp;
475: {
476:
477: switch (tp->t_state) {
478:
479: case TCPS_CLOSED:
480: case TCPS_LISTEN:
481: case TCPS_SYN_SENT:
482: tp->t_state = TCPS_CLOSED;
483: tp = tcp_close(tp);
484: break;
485:
486: case TCPS_SYN_RECEIVED:
487: case TCPS_ESTABLISHED:
488: tp->t_state = TCPS_FIN_WAIT_1;
489: break;
490:
491: case TCPS_CLOSE_WAIT:
492: tp->t_state = TCPS_LAST_ACK;
493: break;
494: }
495: if (tp && tp->t_state >= TCPS_FIN_WAIT_2)
496: soisdisconnected(tp->t_inpcb->inp_socket);
497: return (tp);
498: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.