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