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