[BACK]Return to tcp_usrreq.c CVS log [TXT][DIR] Up to [local] / sys / netinet

Annotation of sys/netinet/tcp_usrreq.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: tcp_usrreq.c,v 1.91 2007/06/25 12:17:43 markus Exp $  */
                      2: /*     $NetBSD: tcp_usrreq.c,v 1.20 1996/02/13 23:44:16 christos Exp $ */
                      3:
                      4: /*
                      5:  * Copyright (c) 1982, 1986, 1988, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  * 3. Neither the name of the University nor the names of its contributors
                     17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  *
                     32:  *     @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
                     33:  *
                     34:  * NRL grants permission for redistribution and use in source and binary
                     35:  * forms, with or without modification, of the software and documentation
                     36:  * created at NRL provided that the following conditions are met:
                     37:  *
                     38:  * 1. Redistributions of source code must retain the above copyright
                     39:  *    notice, this list of conditions and the following disclaimer.
                     40:  * 2. Redistributions in binary form must reproduce the above copyright
                     41:  *    notice, this list of conditions and the following disclaimer in the
                     42:  *    documentation and/or other materials provided with the distribution.
                     43:  * 3. All advertising materials mentioning features or use of this software
                     44:  *    must display the following acknowledgements:
                     45:  *     This product includes software developed by the University of
                     46:  *     California, Berkeley and its contributors.
                     47:  *     This product includes software developed at the Information
                     48:  *     Technology Division, US Naval Research Laboratory.
                     49:  * 4. Neither the name of the NRL nor the names of its contributors
                     50:  *    may be used to endorse or promote products derived from this software
                     51:  *    without specific prior written permission.
                     52:  *
                     53:  * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
                     54:  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     55:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
                     56:  * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
                     57:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     58:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     59:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
                     60:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                     61:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                     62:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     63:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     64:  *
                     65:  * The views and conclusions contained in the software and documentation
                     66:  * are those of the authors and should not be interpreted as representing
                     67:  * official policies, either expressed or implied, of the US Naval
                     68:  * Research Laboratory (NRL).
                     69:  */
                     70:
                     71: #include <sys/param.h>
                     72: #include <sys/systm.h>
                     73: #include <sys/mbuf.h>
                     74: #include <sys/socket.h>
                     75: #include <sys/socketvar.h>
                     76: #include <sys/protosw.h>
                     77: #include <sys/stat.h>
                     78: #include <sys/sysctl.h>
                     79: #include <sys/domain.h>
                     80: #include <sys/kernel.h>
                     81:
                     82: #include <dev/rndvar.h>
                     83:
                     84: #include <net/if.h>
                     85: #include <net/route.h>
                     86:
                     87: #include <netinet/in.h>
                     88: #include <netinet/in_systm.h>
                     89: #include <netinet/in_var.h>
                     90: #include <netinet/ip.h>
                     91: #include <netinet/in_pcb.h>
                     92: #include <netinet/ip_var.h>
                     93: #include <netinet/tcp.h>
                     94: #include <netinet/tcp_fsm.h>
                     95: #include <netinet/tcp_seq.h>
                     96: #include <netinet/tcp_timer.h>
                     97: #include <netinet/tcp_var.h>
                     98: #include <netinet/tcpip.h>
                     99: #include <netinet/tcp_debug.h>
                    100:
                    101: /*
                    102:  * TCP protocol interface to socket abstraction.
                    103:  */
                    104: extern char *tcpstates[];
                    105: extern int tcptv_keep_init;
                    106:
                    107: extern int tcp_rst_ppslim;
                    108:
                    109: /* from in_pcb.c */
                    110: extern struct baddynamicports baddynamicports;
                    111:
                    112: #ifndef TCP_SENDSPACE
                    113: #define        TCP_SENDSPACE   1024*16
                    114: #endif
                    115: u_int  tcp_sendspace = TCP_SENDSPACE;
                    116: #ifndef TCP_RECVSPACE
                    117: #define        TCP_RECVSPACE   1024*16
                    118: #endif
                    119: u_int  tcp_recvspace = TCP_RECVSPACE;
                    120:
                    121: int *tcpctl_vars[TCPCTL_MAXID] = TCPCTL_VARS;
                    122:
                    123: struct inpcbtable tcbtable;
                    124:
                    125: int tcp_ident(void *, size_t *, void *, size_t, int);
                    126:
                    127: #ifdef INET6
                    128: int
                    129: tcp6_usrreq(so, req, m, nam, control, p)
                    130:        struct socket *so;
                    131:        int req;
                    132:        struct mbuf *m, *nam, *control;
                    133:        struct proc *p;
                    134: {
                    135:
                    136:        return tcp_usrreq(so, req, m, nam, control);
                    137: }
                    138: #endif
                    139:
                    140: /*
                    141:  * Process a TCP user request for TCP tb.  If this is a send request
                    142:  * then m is the mbuf chain of send data.  If this is a timer expiration
                    143:  * (called from the software clock routine), then timertype tells which timer.
                    144:  */
                    145: /*ARGSUSED*/
                    146: int
                    147: tcp_usrreq(so, req, m, nam, control)
                    148:        struct socket *so;
                    149:        int req;
                    150:        struct mbuf *m, *nam, *control;
                    151: {
                    152:        struct sockaddr_in *sin;
                    153:        struct inpcb *inp;
                    154:        struct tcpcb *tp = NULL;
                    155:        int s;
                    156:        int error = 0;
                    157:        short ostate;
                    158:
                    159:        if (req == PRU_CONTROL) {
                    160: #ifdef INET6
                    161:                if (sotopf(so) == PF_INET6)
                    162:                        return in6_control(so, (u_long)m, (caddr_t)nam,
                    163:                            (struct ifnet *)control, 0);
                    164:                else
                    165: #endif /* INET6 */
                    166:                        return (in_control(so, (u_long)m, (caddr_t)nam,
                    167:                            (struct ifnet *)control));
                    168:        }
                    169:        if (control && control->m_len) {
                    170:                m_freem(control);
                    171:                if (m)
                    172:                        m_freem(m);
                    173:                return (EINVAL);
                    174:        }
                    175:
                    176:        s = splsoftnet();
                    177:        inp = sotoinpcb(so);
                    178:        /*
                    179:         * When a TCP is attached to a socket, then there will be
                    180:         * a (struct inpcb) pointed at by the socket, and this
                    181:         * structure will point at a subsidiary (struct tcpcb).
                    182:         */
                    183:        if (inp == 0 && req != PRU_ATTACH) {
                    184:                splx(s);
                    185:                /*
                    186:                 * The following corrects an mbuf leak under rare
                    187:                 * circumstances
                    188:                 */
                    189:                if (m && (req == PRU_SEND || req == PRU_SENDOOB))
                    190:                        m_freem(m);
                    191:                return (EINVAL);                /* XXX */
                    192:        }
                    193:        if (inp) {
                    194:                tp = intotcpcb(inp);
                    195:                /* WHAT IF TP IS 0? */
                    196: #ifdef KPROF
                    197:                tcp_acounts[tp->t_state][req]++;
                    198: #endif
                    199:                ostate = tp->t_state;
                    200:        } else
                    201:                ostate = 0;
                    202:        switch (req) {
                    203:
                    204:        /*
                    205:         * TCP attaches to socket via PRU_ATTACH, reserving space,
                    206:         * and an internet control block.
                    207:         */
                    208:        case PRU_ATTACH:
                    209:                if (inp) {
                    210:                        error = EISCONN;
                    211:                        break;
                    212:                }
                    213:                error = tcp_attach(so);
                    214:                if (error)
                    215:                        break;
                    216:                if ((so->so_options & SO_LINGER) && so->so_linger == 0)
                    217:                        so->so_linger = TCP_LINGERTIME;
                    218:                tp = sototcpcb(so);
                    219:                break;
                    220:
                    221:        /*
                    222:         * PRU_DETACH detaches the TCP protocol from the socket.
                    223:         * If the protocol state is non-embryonic, then can't
                    224:         * do this directly: have to initiate a PRU_DISCONNECT,
                    225:         * which may finish later; embryonic TCB's can just
                    226:         * be discarded here.
                    227:         */
                    228:        case PRU_DETACH:
                    229:                tp = tcp_disconnect(tp);
                    230:                break;
                    231:
                    232:        /*
                    233:         * Give the socket an address.
                    234:         */
                    235:        case PRU_BIND:
                    236: #ifdef INET6
                    237:                if (inp->inp_flags & INP_IPV6)
                    238:                        error = in6_pcbbind(inp, nam);
                    239:                else
                    240: #endif
                    241:                        error = in_pcbbind(inp, nam);
                    242:                if (error)
                    243:                        break;
                    244:                break;
                    245:
                    246:        /*
                    247:         * Prepare to accept connections.
                    248:         */
                    249:        case PRU_LISTEN:
                    250:                if (inp->inp_lport == 0) {
                    251: #ifdef INET6
                    252:                        if (inp->inp_flags & INP_IPV6)
                    253:                                error = in6_pcbbind(inp, NULL);
                    254:                        else
                    255: #endif
                    256:                                error = in_pcbbind(inp, NULL);
                    257:                }
                    258:                /* If the in_pcbbind() above is called, the tp->pf
                    259:                   should still be whatever it was before. */
                    260:                if (error == 0)
                    261:                        tp->t_state = TCPS_LISTEN;
                    262:                break;
                    263:
                    264:        /*
                    265:         * Initiate connection to peer.
                    266:         * Create a template for use in transmissions on this connection.
                    267:         * Enter SYN_SENT state, and mark socket as connecting.
                    268:         * Start keep-alive timer, and seed output sequence space.
                    269:         * Send initial segment on connection.
                    270:         */
                    271:        case PRU_CONNECT:
                    272:                sin = mtod(nam, struct sockaddr_in *);
                    273:
                    274: #ifdef INET6
                    275:                if (sin->sin_family == AF_INET6) {
                    276:                        struct in6_addr *in6_addr = &mtod(nam,
                    277:                            struct sockaddr_in6 *)->sin6_addr;
                    278:
                    279:                        if (IN6_IS_ADDR_UNSPECIFIED(in6_addr) ||
                    280:                            IN6_IS_ADDR_MULTICAST(in6_addr) ||
                    281:                            (IN6_IS_ADDR_V4MAPPED(in6_addr) &&
                    282:                            ((in6_addr->s6_addr32[3] == INADDR_ANY) ||
                    283:                            IN_MULTICAST(in6_addr->s6_addr32[3]) ||
                    284:                            in_broadcast(sin->sin_addr, NULL)))) {
                    285:                                error = EINVAL;
                    286:                                break;
                    287:                        }
                    288:
                    289:                        if (inp->inp_lport == 0) {
                    290:                                error = in6_pcbbind(inp, NULL);
                    291:                                if (error)
                    292:                                        break;
                    293:                        }
                    294:                        error = in6_pcbconnect(inp, nam);
                    295:                } else if (sin->sin_family == AF_INET)
                    296: #endif /* INET6 */
                    297:                {
                    298:                        if ((sin->sin_addr.s_addr == INADDR_ANY) ||
                    299:                            IN_MULTICAST(sin->sin_addr.s_addr) ||
                    300:                            in_broadcast(sin->sin_addr, NULL)) {
                    301:                                error = EINVAL;
                    302:                                break;
                    303:                        }
                    304:
                    305:                        if (inp->inp_lport == 0) {
                    306:                                error = in_pcbbind(inp, NULL);
                    307:                                if (error)
                    308:                                        break;
                    309:                        }
                    310:                        error = in_pcbconnect(inp, nam);
                    311:                }
                    312:
                    313:                if (error)
                    314:                        break;
                    315:
                    316:                tp->t_template = tcp_template(tp);
                    317:                if (tp->t_template == 0) {
                    318:                        in_pcbdisconnect(inp);
                    319:                        error = ENOBUFS;
                    320:                        break;
                    321:                }
                    322:
                    323:                so->so_state |= SS_CONNECTOUT;
                    324:
                    325:                /* Compute window scaling to request.  */
                    326:                tcp_rscale(tp, so->so_rcv.sb_hiwat);
                    327:
                    328:                soisconnecting(so);
                    329:                tcpstat.tcps_connattempt++;
                    330:                tp->t_state = TCPS_SYN_SENT;
                    331:                TCP_TIMER_ARM(tp, TCPT_KEEP, tcptv_keep_init);
                    332: #ifdef TCP_COMPAT_42
                    333:                tp->iss = tcp_iss;
                    334:                tcp_iss += TCP_ISSINCR/2;
                    335: #else  /* TCP_COMPAT_42 */
                    336:                tcp_set_iss_tsm(tp);
                    337: #endif /* !TCP_COMPAT_42 */
                    338:                tcp_sendseqinit(tp);
                    339: #if defined(TCP_SACK)
                    340:                tp->snd_last = tp->snd_una;
                    341: #endif
                    342: #if defined(TCP_SACK) && defined(TCP_FACK)
                    343:                tp->snd_fack = tp->snd_una;
                    344:                tp->retran_data = 0;
                    345:                tp->snd_awnd = 0;
                    346: #endif
                    347:                error = tcp_output(tp);
                    348:                break;
                    349:
                    350:        /*
                    351:         * Create a TCP connection between two sockets.
                    352:         */
                    353:        case PRU_CONNECT2:
                    354:                error = EOPNOTSUPP;
                    355:                break;
                    356:
                    357:        /*
                    358:         * Initiate disconnect from peer.
                    359:         * If connection never passed embryonic stage, just drop;
                    360:         * else if don't need to let data drain, then can just drop anyways,
                    361:         * else have to begin TCP shutdown process: mark socket disconnecting,
                    362:         * drain unread data, state switch to reflect user close, and
                    363:         * send segment (e.g. FIN) to peer.  Socket will be really disconnected
                    364:         * when peer sends FIN and acks ours.
                    365:         *
                    366:         * SHOULD IMPLEMENT LATER PRU_CONNECT VIA REALLOC TCPCB.
                    367:         */
                    368:        case PRU_DISCONNECT:
                    369:                tp = tcp_disconnect(tp);
                    370:                break;
                    371:
                    372:        /*
                    373:         * Accept a connection.  Essentially all the work is
                    374:         * done at higher levels; just return the address
                    375:         * of the peer, storing through addr.
                    376:         */
                    377:        case PRU_ACCEPT:
                    378: #ifdef INET6
                    379:                if (inp->inp_flags & INP_IPV6)
                    380:                        in6_setpeeraddr(inp, nam);
                    381:                else
                    382: #endif
                    383:                        in_setpeeraddr(inp, nam);
                    384:                break;
                    385:
                    386:        /*
                    387:         * Mark the connection as being incapable of further output.
                    388:         */
                    389:        case PRU_SHUTDOWN:
                    390:                if (so->so_state & SS_CANTSENDMORE)
                    391:                        break;
                    392:                socantsendmore(so);
                    393:                tp = tcp_usrclosed(tp);
                    394:                if (tp)
                    395:                        error = tcp_output(tp);
                    396:                break;
                    397:
                    398:        /*
                    399:         * After a receive, possibly send window update to peer.
                    400:         */
                    401:        case PRU_RCVD:
                    402:                /*
                    403:                 * soreceive() calls this function when a user receives
                    404:                 * ancillary data on a listening socket. We don't call
                    405:                 * tcp_output in such a case, since there is no header
                    406:                 * template for a listening socket and hence the kernel
                    407:                 * will panic.
                    408:                 */
                    409:                if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) != 0)
                    410:                        (void) tcp_output(tp);
                    411:                break;
                    412:
                    413:        /*
                    414:         * Do a send by putting data in output queue and updating urgent
                    415:         * marker if URG set.  Possibly send more data.
                    416:         */
                    417:        case PRU_SEND:
                    418:                sbappendstream(&so->so_snd, m);
                    419:                error = tcp_output(tp);
                    420:                break;
                    421:
                    422:        /*
                    423:         * Abort the TCP.
                    424:         */
                    425:        case PRU_ABORT:
                    426:                tp = tcp_drop(tp, ECONNABORTED);
                    427:                break;
                    428:
                    429:        case PRU_SENSE:
                    430:                ((struct stat *) m)->st_blksize = so->so_snd.sb_hiwat;
                    431:                splx(s);
                    432:                return (0);
                    433:
                    434:        case PRU_RCVOOB:
                    435:                if ((so->so_oobmark == 0 &&
                    436:                    (so->so_state & SS_RCVATMARK) == 0) ||
                    437:                    so->so_options & SO_OOBINLINE ||
                    438:                    tp->t_oobflags & TCPOOB_HADDATA) {
                    439:                        error = EINVAL;
                    440:                        break;
                    441:                }
                    442:                if ((tp->t_oobflags & TCPOOB_HAVEDATA) == 0) {
                    443:                        error = EWOULDBLOCK;
                    444:                        break;
                    445:                }
                    446:                m->m_len = 1;
                    447:                *mtod(m, caddr_t) = tp->t_iobc;
                    448:                if (((long)nam & MSG_PEEK) == 0)
                    449:                        tp->t_oobflags ^= (TCPOOB_HAVEDATA | TCPOOB_HADDATA);
                    450:                break;
                    451:
                    452:        case PRU_SENDOOB:
                    453:                if (sbspace(&so->so_snd) < -512) {
                    454:                        m_freem(m);
                    455:                        error = ENOBUFS;
                    456:                        break;
                    457:                }
                    458:                /*
                    459:                 * According to RFC961 (Assigned Protocols),
                    460:                 * the urgent pointer points to the last octet
                    461:                 * of urgent data.  We continue, however,
                    462:                 * to consider it to indicate the first octet
                    463:                 * of data past the urgent section.
                    464:                 * Otherwise, snd_up should be one lower.
                    465:                 */
                    466:                sbappendstream(&so->so_snd, m);
                    467:                tp->snd_up = tp->snd_una + so->so_snd.sb_cc;
                    468:                tp->t_force = 1;
                    469:                error = tcp_output(tp);
                    470:                tp->t_force = 0;
                    471:                break;
                    472:
                    473:        case PRU_SOCKADDR:
                    474: #ifdef INET6
                    475:                if (inp->inp_flags & INP_IPV6)
                    476:                        in6_setsockaddr(inp, nam);
                    477:                else
                    478: #endif
                    479:                        in_setsockaddr(inp, nam);
                    480:                break;
                    481:
                    482:        case PRU_PEERADDR:
                    483: #ifdef INET6
                    484:                if (inp->inp_flags & INP_IPV6)
                    485:                        in6_setpeeraddr(inp, nam);
                    486:                else
                    487: #endif
                    488:                        in_setpeeraddr(inp, nam);
                    489:                break;
                    490:
                    491:        default:
                    492:                panic("tcp_usrreq");
                    493:        }
                    494:        if (tp && (so->so_options & SO_DEBUG))
                    495:                tcp_trace(TA_USER, ostate, tp, (caddr_t)0, req, 0);
                    496:        splx(s);
                    497:        return (error);
                    498: }
                    499:
                    500: int
                    501: tcp_ctloutput(op, so, level, optname, mp)
                    502:        int op;
                    503:        struct socket *so;
                    504:        int level, optname;
                    505:        struct mbuf **mp;
                    506: {
                    507:        int error = 0, s;
                    508:        struct inpcb *inp;
                    509:        struct tcpcb *tp;
                    510:        struct mbuf *m;
                    511:        int i;
                    512:
                    513:        s = splsoftnet();
                    514:        inp = sotoinpcb(so);
                    515:        if (inp == NULL) {
                    516:                splx(s);
                    517:                if (op == PRCO_SETOPT && *mp)
                    518:                        (void) m_free(*mp);
                    519:                return (ECONNRESET);
                    520:        }
                    521: #ifdef INET6
                    522:        tp = intotcpcb(inp);
                    523: #endif /* INET6 */
                    524:        if (level != IPPROTO_TCP) {
                    525:                switch (so->so_proto->pr_domain->dom_family) {
                    526: #ifdef INET6
                    527:                case PF_INET6:
                    528:                        error = ip6_ctloutput(op, so, level, optname, mp);
                    529:                        break;
                    530: #endif /* INET6 */
                    531:                case PF_INET:
                    532:                        error = ip_ctloutput(op, so, level, optname, mp);
                    533:                        break;
                    534:                default:
                    535:                        error = EAFNOSUPPORT;   /*?*/
                    536:                        break;
                    537:                }
                    538:                splx(s);
                    539:                return (error);
                    540:        }
                    541: #ifndef INET6
                    542:        tp = intotcpcb(inp);
                    543: #endif /* !INET6 */
                    544:
                    545:        switch (op) {
                    546:
                    547:        case PRCO_SETOPT:
                    548:                m = *mp;
                    549:                switch (optname) {
                    550:
                    551:                case TCP_NODELAY:
                    552:                        if (m == NULL || m->m_len < sizeof (int))
                    553:                                error = EINVAL;
                    554:                        else if (*mtod(m, int *))
                    555:                                tp->t_flags |= TF_NODELAY;
                    556:                        else
                    557:                                tp->t_flags &= ~TF_NODELAY;
                    558:                        break;
                    559:
                    560:                case TCP_MAXSEG:
                    561:                        if (m == NULL || m->m_len < sizeof (int)) {
                    562:                                error = EINVAL;
                    563:                                break;
                    564:                        }
                    565:
                    566:                        i = *mtod(m, int *);
                    567:                        if (i > 0 && i <= tp->t_maxseg)
                    568:                                tp->t_maxseg = i;
                    569:                        else
                    570:                                error = EINVAL;
                    571:                        break;
                    572:
                    573: #ifdef TCP_SACK
                    574:                case TCP_SACK_ENABLE:
                    575:                        if (m == NULL || m->m_len < sizeof (int)) {
                    576:                                error = EINVAL;
                    577:                                break;
                    578:                        }
                    579:
                    580:                        if (TCPS_HAVEESTABLISHED(tp->t_state)) {
                    581:                                error = EPERM;
                    582:                                break;
                    583:                        }
                    584:
                    585:                        if (tp->t_flags & TF_SIGNATURE) {
                    586:                                error = EPERM;
                    587:                                break;
                    588:                        }
                    589:
                    590:                        if (*mtod(m, int *))
                    591:                                tp->sack_enable = 1;
                    592:                        else
                    593:                                tp->sack_enable = 0;
                    594:                        break;
                    595: #endif
                    596: #ifdef TCP_SIGNATURE
                    597:                case TCP_MD5SIG:
                    598:                        if (m == NULL || m->m_len < sizeof (int)) {
                    599:                                error = EINVAL;
                    600:                                break;
                    601:                        }
                    602:
                    603:                        if (TCPS_HAVEESTABLISHED(tp->t_state)) {
                    604:                                error = EPERM;
                    605:                                break;
                    606:                        }
                    607:
                    608:                        if (*mtod(m, int *)) {
                    609:                                tp->t_flags |= TF_SIGNATURE;
                    610: #ifdef TCP_SACK
                    611:                                tp->sack_enable = 0;
                    612: #endif /* TCP_SACK */
                    613:                        } else
                    614:                                tp->t_flags &= ~TF_SIGNATURE;
                    615:                        break;
                    616: #endif /* TCP_SIGNATURE */
                    617:                default:
                    618:                        error = ENOPROTOOPT;
                    619:                        break;
                    620:                }
                    621:                if (m)
                    622:                        (void) m_free(m);
                    623:                break;
                    624:
                    625:        case PRCO_GETOPT:
                    626:                *mp = m = m_get(M_WAIT, MT_SOOPTS);
                    627:                m->m_len = sizeof(int);
                    628:
                    629:                switch (optname) {
                    630:                case TCP_NODELAY:
                    631:                        *mtod(m, int *) = tp->t_flags & TF_NODELAY;
                    632:                        break;
                    633:                case TCP_MAXSEG:
                    634:                        *mtod(m, int *) = tp->t_maxseg;
                    635:                        break;
                    636: #ifdef TCP_SACK
                    637:                case TCP_SACK_ENABLE:
                    638:                        *mtod(m, int *) = tp->sack_enable;
                    639:                        break;
                    640: #endif
                    641: #ifdef TCP_SIGNATURE
                    642:                case TCP_MD5SIG:
                    643:                        *mtod(m, int *) = tp->t_flags & TF_SIGNATURE;
                    644:                        break;
                    645: #endif
                    646:                default:
                    647:                        error = ENOPROTOOPT;
                    648:                        break;
                    649:                }
                    650:                break;
                    651:        }
                    652:        splx(s);
                    653:        return (error);
                    654: }
                    655:
                    656: /*
                    657:  * Attach TCP protocol to socket, allocating
                    658:  * internet protocol control block, tcp control block,
                    659:  * bufer space, and entering LISTEN state if to accept connections.
                    660:  */
                    661: int
                    662: tcp_attach(so)
                    663:        struct socket *so;
                    664: {
                    665:        struct tcpcb *tp;
                    666:        struct inpcb *inp;
                    667:        int error;
                    668:
                    669:        if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
                    670:                error = soreserve(so, tcp_sendspace, tcp_recvspace);
                    671:                if (error)
                    672:                        return (error);
                    673:        }
                    674:        error = in_pcballoc(so, &tcbtable);
                    675:        if (error)
                    676:                return (error);
                    677:        inp = sotoinpcb(so);
                    678:        tp = tcp_newtcpcb(inp);
                    679:        if (tp == NULL) {
                    680:                int nofd = so->so_state & SS_NOFDREF;   /* XXX */
                    681:
                    682:                so->so_state &= ~SS_NOFDREF;    /* don't free the socket yet */
                    683:                in_pcbdetach(inp);
                    684:                so->so_state |= nofd;
                    685:                return (ENOBUFS);
                    686:        }
                    687:        tp->t_state = TCPS_CLOSED;
                    688: #ifdef INET6
                    689:        /* we disallow IPv4 mapped address completely. */
                    690:        if (inp->inp_flags & INP_IPV6)
                    691:                tp->pf = PF_INET6;
                    692:        else
                    693:                tp->pf = PF_INET;
                    694: #else
                    695:        tp->pf = PF_INET;
                    696: #endif
                    697:        return (0);
                    698: }
                    699:
                    700: /*
                    701:  * Initiate (or continue) disconnect.
                    702:  * If embryonic state, just send reset (once).
                    703:  * If in ``let data drain'' option and linger null, just drop.
                    704:  * Otherwise (hard), mark socket disconnecting and drop
                    705:  * current input data; switch states based on user close, and
                    706:  * send segment to peer (with FIN).
                    707:  */
                    708: struct tcpcb *
                    709: tcp_disconnect(tp)
                    710:        struct tcpcb *tp;
                    711: {
                    712:        struct socket *so = tp->t_inpcb->inp_socket;
                    713:
                    714:        if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
                    715:                tp = tcp_close(tp);
                    716:        else if ((so->so_options & SO_LINGER) && so->so_linger == 0)
                    717:                tp = tcp_drop(tp, 0);
                    718:        else {
                    719:                soisdisconnecting(so);
                    720:                sbflush(&so->so_rcv);
                    721:                tp = tcp_usrclosed(tp);
                    722:                if (tp)
                    723:                        (void) tcp_output(tp);
                    724:        }
                    725:        return (tp);
                    726: }
                    727:
                    728: /*
                    729:  * User issued close, and wish to trail through shutdown states:
                    730:  * if never received SYN, just forget it.  If got a SYN from peer,
                    731:  * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN.
                    732:  * If already got a FIN from peer, then almost done; go to LAST_ACK
                    733:  * state.  In all other cases, have already sent FIN to peer (e.g.
                    734:  * after PRU_SHUTDOWN), and just have to play tedious game waiting
                    735:  * for peer to send FIN or not respond to keep-alives, etc.
                    736:  * We can let the user exit from the close as soon as the FIN is acked.
                    737:  */
                    738: struct tcpcb *
                    739: tcp_usrclosed(tp)
                    740:        struct tcpcb *tp;
                    741: {
                    742:
                    743:        switch (tp->t_state) {
                    744:
                    745:        case TCPS_CLOSED:
                    746:        case TCPS_LISTEN:
                    747:        case TCPS_SYN_SENT:
                    748:                tp->t_state = TCPS_CLOSED;
                    749:                tp = tcp_close(tp);
                    750:                break;
                    751:
                    752:        case TCPS_SYN_RECEIVED:
                    753:        case TCPS_ESTABLISHED:
                    754:                tp->t_state = TCPS_FIN_WAIT_1;
                    755:                break;
                    756:
                    757:        case TCPS_CLOSE_WAIT:
                    758:                tp->t_state = TCPS_LAST_ACK;
                    759:                break;
                    760:        }
                    761:        if (tp && tp->t_state >= TCPS_FIN_WAIT_2) {
                    762:                soisdisconnected(tp->t_inpcb->inp_socket);
                    763:                /*
                    764:                 * If we are in FIN_WAIT_2, we arrived here because the
                    765:                 * application did a shutdown of the send side.  Like the
                    766:                 * case of a transition from FIN_WAIT_1 to FIN_WAIT_2 after
                    767:                 * a full close, we start a timer to make sure sockets are
                    768:                 * not left in FIN_WAIT_2 forever.
                    769:                 */
                    770:                if (tp->t_state == TCPS_FIN_WAIT_2)
                    771:                        TCP_TIMER_ARM(tp, TCPT_2MSL, tcp_maxidle);
                    772:        }
                    773:        return (tp);
                    774: }
                    775:
                    776: /*
                    777:  * Look up a socket for ident or tcpdrop, ...
                    778:  */
                    779: int
                    780: tcp_ident(oldp, oldlenp, newp, newlen, dodrop)
                    781:        void *oldp;
                    782:        size_t *oldlenp;
                    783:        void *newp;
                    784:        size_t newlen;
                    785:        int dodrop;
                    786: {
                    787:        int error = 0, s;
                    788:        struct tcp_ident_mapping tir;
                    789:        struct inpcb *inp;
                    790:        struct tcpcb *tp = NULL;
                    791:        struct sockaddr_in *fin, *lin;
                    792: #ifdef INET6
                    793:        struct sockaddr_in6 *fin6, *lin6;
                    794:        struct in6_addr f6, l6;
                    795: #endif
                    796:        if (dodrop) {
                    797:                if (oldp != NULL || *oldlenp != 0)
                    798:                        return (EINVAL);
                    799:                if (newp == NULL)
                    800:                        return (EPERM);
                    801:                if (newlen < sizeof(tir))
                    802:                        return (ENOMEM);
                    803:                if ((error = copyin(newp, &tir, sizeof (tir))) != 0 )
                    804:                        return (error);
                    805:        } else {
                    806:                if (oldp == NULL)
                    807:                        return (EINVAL);
                    808:                if (*oldlenp < sizeof(tir))
                    809:                        return (ENOMEM);
                    810:                if (newp != NULL || newlen != 0)
                    811:                        return (EINVAL);
                    812:                if ((error = copyin(oldp, &tir, sizeof (tir))) != 0 )
                    813:                        return (error);
                    814:        }
                    815:        switch (tir.faddr.ss_family) {
                    816: #ifdef INET6
                    817:        case AF_INET6:
                    818:                fin6 = (struct sockaddr_in6 *)&tir.faddr;
                    819:                error = in6_embedscope(&f6, fin6, NULL, NULL);
                    820:                if (error)
                    821:                        return EINVAL;  /*?*/
                    822:                lin6 = (struct sockaddr_in6 *)&tir.laddr;
                    823:                error = in6_embedscope(&l6, lin6, NULL, NULL);
                    824:                if (error)
                    825:                        return EINVAL;  /*?*/
                    826:                break;
                    827: #endif
                    828:        case AF_INET:
                    829:                fin = (struct sockaddr_in *)&tir.faddr;
                    830:                lin = (struct sockaddr_in *)&tir.laddr;
                    831:                break;
                    832:        default:
                    833:                return (EINVAL);
                    834:        }
                    835:
                    836:        s = splsoftnet();
                    837:        switch (tir.faddr.ss_family) {
                    838: #ifdef INET6
                    839:        case AF_INET6:
                    840:                inp = in6_pcbhashlookup(&tcbtable, &f6,
                    841:                    fin6->sin6_port, &l6, lin6->sin6_port);
                    842:                break;
                    843: #endif
                    844:        case AF_INET:
                    845:                inp = in_pcbhashlookup(&tcbtable,  fin->sin_addr,
                    846:                    fin->sin_port, lin->sin_addr, lin->sin_port);
                    847:                break;
                    848:        }
                    849:
                    850:        if (dodrop) {
                    851:                if (inp && (tp = intotcpcb(inp)) &&
                    852:                    ((inp->inp_socket->so_options & SO_ACCEPTCONN) == 0))
                    853:                        tp = tcp_drop(tp, ECONNABORTED);
                    854:                else
                    855:                        error = ESRCH;
                    856:                splx(s);
                    857:                return (error);
                    858:        }
                    859:
                    860:        if (inp == NULL) {
                    861:                ++tcpstat.tcps_pcbhashmiss;
                    862:                switch (tir.faddr.ss_family) {
                    863: #ifdef INET6
                    864:                case AF_INET6:
                    865:                        inp = in6_pcblookup_listen(&tcbtable,
                    866:                            &l6, lin6->sin6_port, 0);
                    867:                        break;
                    868: #endif
                    869:                case AF_INET:
                    870:                        inp = in_pcblookup_listen(&tcbtable,
                    871:                            lin->sin_addr, lin->sin_port, 0);
                    872:                        break;
                    873:                }
                    874:        }
                    875:
                    876:        if (inp != NULL && (inp->inp_socket->so_state & SS_CONNECTOUT)) {
                    877:                tir.ruid = inp->inp_socket->so_ruid;
                    878:                tir.euid = inp->inp_socket->so_euid;
                    879:        } else {
                    880:                tir.ruid = -1;
                    881:                tir.euid = -1;
                    882:        }
                    883:        splx(s);
                    884:
                    885:        *oldlenp = sizeof (tir);
                    886:        error = copyout((void *)&tir, oldp, sizeof (tir));
                    887:        return (error);
                    888: }
                    889:
                    890: /*
                    891:  * Sysctl for tcp variables.
                    892:  */
                    893: int
                    894: tcp_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
                    895:        int *name;
                    896:        u_int namelen;
                    897:        void *oldp;
                    898:        size_t *oldlenp;
                    899:        void *newp;
                    900:        size_t newlen;
                    901: {
                    902:        int error, nval;
                    903:
                    904:        /* All sysctl names at this level are terminal. */
                    905:        if (namelen != 1)
                    906:                return (ENOTDIR);
                    907:
                    908:        switch (name[0]) {
                    909: #ifdef TCP_SACK
                    910:        case TCPCTL_SACK:
                    911:                return (sysctl_int(oldp, oldlenp, newp, newlen,
                    912:                    &tcp_do_sack));
                    913: #endif
                    914:        case TCPCTL_SLOWHZ:
                    915:                return (sysctl_rdint(oldp, oldlenp, newp, PR_SLOWHZ));
                    916:
                    917:        case TCPCTL_BADDYNAMIC:
                    918:                return (sysctl_struct(oldp, oldlenp, newp, newlen,
                    919:                    baddynamicports.tcp, sizeof(baddynamicports.tcp)));
                    920:
                    921:        case TCPCTL_IDENT:
                    922:                return (tcp_ident(oldp, oldlenp, newp, newlen, 0));
                    923:
                    924:        case TCPCTL_DROP:
                    925:                return (tcp_ident(oldp, oldlenp, newp, newlen, 1));
                    926:
                    927: #ifdef TCP_ECN
                    928:        case TCPCTL_ECN:
                    929:                return (sysctl_int(oldp, oldlenp, newp, newlen,
                    930:                   &tcp_do_ecn));
                    931: #endif
                    932:        case TCPCTL_REASS_LIMIT:
                    933:                nval = tcp_reass_limit;
                    934:                error = sysctl_int(oldp, oldlenp, newp, newlen, &nval);
                    935:                if (error)
                    936:                        return (error);
                    937:                if (nval != tcp_reass_limit) {
                    938:                        error = pool_sethardlimit(&tcpqe_pool, nval, NULL, 0);
                    939:                        if (error)
                    940:                                return (error);
                    941:                        tcp_reass_limit = nval;
                    942:                }
                    943:                return (0);
                    944: #ifdef TCP_SACK
                    945:        case TCPCTL_SACKHOLE_LIMIT:
                    946:                nval = tcp_sackhole_limit;
                    947:                error = sysctl_int(oldp, oldlenp, newp, newlen, &nval);
                    948:                if (error)
                    949:                        return (error);
                    950:                if (nval != tcp_sackhole_limit) {
                    951:                        error = pool_sethardlimit(&sackhl_pool, nval, NULL, 0);
                    952:                        if (error)
                    953:                                return (error);
                    954:                        tcp_sackhole_limit = nval;
                    955:                }
                    956:                return (0);
                    957: #endif
                    958:        default:
                    959:                if (name[0] < TCPCTL_MAXID)
                    960:                        return (sysctl_int_arr(tcpctl_vars, name, namelen,
                    961:                            oldp, oldlenp, newp, newlen));
                    962:                return (ENOPROTOOPT);
                    963:        }
                    964:        /* NOTREACHED */
                    965: }

CVSweb