Annotation of kernel/bsd/nfs/krpc_subr.c, revision 1.1

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) 1994 Gordon Ross, Adam Glass 
        !            28:  * Copyright (c) 1992 Regents of the University of California.
        !            29:  * All rights reserved.
        !            30:  *
        !            31:  * The NEXTSTEP Software License Agreement specifies the terms
        !            32:  * and conditions for redistribution.
        !            33:  *
        !            34:  * This software was developed by the Computer Systems Engineering group
        !            35:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
        !            36:  * contributed to Berkeley.
        !            37:  *
        !            38:  * Redistribution and use in source and binary forms, with or without
        !            39:  * modification, are permitted provided that the following conditions
        !            40:  * are met:
        !            41:  * 1. Redistributions of source code must retain the above copyright
        !            42:  *    notice, this list of conditions and the following disclaimer.
        !            43:  * 2. Redistributions in binary form must reproduce the above copyright
        !            44:  *    notice, this list of conditions and the following disclaimer in the
        !            45:  *    documentation and/or other materials provided with the distribution.
        !            46:  * 3. All advertising materials mentioning features or use of this software
        !            47:  *    must display the following acknowledgement:
        !            48:  *     This product includes software developed by the University of
        !            49:  *     California, Lawrence Berkeley Laboratory and its contributors.
        !            50:  * 4. Neither the name of the University nor the names of its contributors
        !            51:  *    may be used to endorse or promote products derived from this software
        !            52:  *    without specific prior written permission.
        !            53:  *
        !            54:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            55:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            56:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            57:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            58:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            59:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            60:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            61:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            62:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            63:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            64:  * SUCH DAMAGE.
        !            65:  *
        !            66:  */
        !            67: 
        !            68: #include <sys/param.h>
        !            69: #include <sys/conf.h>
        !            70: #include <sys/ioctl.h>
        !            71: #include <sys/proc.h>
        !            72: #include <sys/mount.h>
        !            73: #include <sys/mbuf.h>
        !            74: #include <sys/socket.h>
        !            75: #include <sys/systm.h>
        !            76: #include <sys/reboot.h>
        !            77: 
        !            78: #include <net/if.h>
        !            79: #include <netinet/in.h>
        !            80: 
        !            81: #include <nfs/rpcv2.h>
        !            82: #include <nfs/krpc.h>
        !            83: 
        !            84: /*
        !            85:  * Kernel support for Sun RPC
        !            86:  *
        !            87:  * Used currently for bootstrapping in nfs diskless configurations.
        !            88:  * 
        !            89:  * Note: will not work on variable-sized rpc args/results.
        !            90:  *       implicit size-limit of an mbuf.
        !            91:  */
        !            92: 
        !            93: /*
        !            94:  * Generic RPC headers
        !            95:  */
        !            96: 
        !            97: struct auth_info {
        !            98:        u_int32_t       rp_atype;       /* auth type */
        !            99:        u_int32_t       rp_alen;        /* auth length */
        !           100: };
        !           101: 
        !           102: struct rpc_call {
        !           103:        u_int32_t       rp_xid;         /* request transaction id */
        !           104:        int32_t         rp_direction;   /* call direction (0) */
        !           105:        u_int32_t       rp_rpcvers;     /* rpc version (2) */
        !           106:        u_int32_t       rp_prog;        /* program */
        !           107:        u_int32_t       rp_vers;        /* version */
        !           108:        u_int32_t       rp_proc;        /* procedure */
        !           109:        struct  auth_info rp_auth;
        !           110:        struct  auth_info rp_verf;
        !           111: };
        !           112: 
        !           113: struct rpc_reply {
        !           114:        u_int32_t rp_xid;               /* request transaction id */
        !           115:        int32_t  rp_direction;          /* call direction (1) */
        !           116:        int32_t  rp_astatus;            /* accept status (0: accepted) */
        !           117:        union {
        !           118:                u_int32_t rpu_errno;
        !           119:                struct {
        !           120:                        struct auth_info rp_auth;
        !           121:                        u_int32_t       rp_rstatus;
        !           122:                } rpu_ok;
        !           123:        } rp_u;
        !           124: };
        !           125: 
        !           126: #define MIN_REPLY_HDR 16       /* xid, dir, astat, errno */
        !           127: 
        !           128: /*
        !           129:  * What is the longest we will wait before re-sending a request?
        !           130:  * Note this is also the frequency of "RPC timeout" messages.
        !           131:  * The re-send loop count sup linearly to this maximum, so the
        !           132:  * first complaint will happen after (1+2+3+4+5)=15 seconds.
        !           133:  */
        !           134: #define        MAX_RESEND_DELAY 5      /* seconds */
        !           135: 
        !           136: /*
        !           137:  * Call portmap to lookup a port number for a particular rpc program
        !           138:  * Returns non-zero error on failure.
        !           139:  */
        !           140: int
        !           141: krpc_portmap(sin,  prog, vers, portp)
        !           142:        struct sockaddr_in *sin;                /* server address */
        !           143:        u_int prog, vers;       /* host order */
        !           144:        u_int16_t *portp;       /* network order */
        !           145: {
        !           146:        struct sdata {
        !           147:                u_int32_t prog;         /* call program */
        !           148:                u_int32_t vers;         /* call version */
        !           149:                u_int32_t proto;        /* call protocol */
        !           150:                u_int32_t port;         /* call port (unused) */
        !           151:        } *sdata;
        !           152:        struct rdata {
        !           153:                u_int16_t pad;
        !           154:                u_int16_t port;
        !           155:        } *rdata;
        !           156:        struct mbuf *m;
        !           157:        int error;
        !           158: 
        !           159:        /* The portmapper port is fixed. */
        !           160:        if (prog == PMAPPROG) {
        !           161:                *portp = htons(PMAPPORT);
        !           162:                return 0;
        !           163:        }
        !           164: 
        !           165:        m = m_gethdr(M_WAIT, MT_DATA);
        !           166:        if (m == NULL)
        !           167:                return ENOBUFS;
        !           168:        m->m_len = sizeof(*sdata);
        !           169:        m->m_pkthdr.len = m->m_len;
        !           170:        sdata = mtod(m, struct sdata *);
        !           171: 
        !           172:        /* Do the RPC to get it. */
        !           173:        sdata->prog = htonl(prog);
        !           174:        sdata->vers = htonl(vers);
        !           175:        sdata->proto = htonl(IPPROTO_UDP);
        !           176:        sdata->port = 0;
        !           177: 
        !           178:        sin->sin_port = htons(PMAPPORT);
        !           179:        error = krpc_call(sin, PMAPPROG, PMAPVERS,
        !           180:                                          PMAPPROC_GETPORT, &m, NULL);
        !           181:        if (error) 
        !           182:                return error;
        !           183: 
        !           184:        rdata = mtod(m, struct rdata *);
        !           185:        *portp = rdata->port;
        !           186: 
        !           187:        m_freem(m);
        !           188:        return 0;
        !           189: }
        !           190: 
        !           191: /*
        !           192:  * Do a remote procedure call (RPC) and wait for its reply.
        !           193:  * If from_p is non-null, then we are doing broadcast, and
        !           194:  * the address from whence the response came is saved there.
        !           195:  */
        !           196: int
        !           197: krpc_call(sa, prog, vers, func, data, from_p)
        !           198:        struct sockaddr_in *sa;
        !           199:        u_int prog, vers, func;
        !           200:        struct mbuf **data;     /* input/output */
        !           201:        struct mbuf **from_p;   /* output */
        !           202: {
        !           203:        struct socket *so;
        !           204:        struct sockaddr_in *sin;
        !           205:        struct mbuf *m, *nam, *mhead, *from;
        !           206:        struct rpc_call *call;
        !           207:        struct rpc_reply *reply;
        !           208:        struct uio auio;
        !           209:        int error, rcvflg, timo, secs, len;
        !           210:        static u_int32_t xid = ~0xFF;
        !           211:        u_int16_t tport;
        !           212: 
        !           213:        /*
        !           214:         * Validate address family.
        !           215:         * Sorry, this is INET specific...
        !           216:         */
        !           217:        if (sa->sin_family != AF_INET)
        !           218:                return (EAFNOSUPPORT);
        !           219: 
        !           220:        /* Free at end if not null. */
        !           221:        nam = mhead = NULL;
        !           222:        from = NULL;
        !           223: 
        !           224:        /*
        !           225:         * Create socket and set its recieve timeout.
        !           226:         */
        !           227:        if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
        !           228:                goto out;
        !           229: 
        !           230:        m = m_get(M_WAIT, MT_SOOPTS);
        !           231:        if (m == NULL) {
        !           232:                error = ENOBUFS;
        !           233:                goto out;
        !           234:        } else {
        !           235:                struct timeval *tv;
        !           236:                tv = mtod(m, struct timeval *);
        !           237:                m->m_len = sizeof(*tv);
        !           238:                tv->tv_sec = 1;
        !           239:                tv->tv_usec = 0;
        !           240:                if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
        !           241:                        goto out;
        !           242:        }
        !           243: 
        !           244:        /*
        !           245:         * Enable broadcast if necessary.
        !           246:         */
        !           247:        if (from_p) {
        !           248:                int32_t *on;
        !           249:                m = m_get(M_WAIT, MT_SOOPTS);
        !           250:                if (m == NULL) {
        !           251:                        error = ENOBUFS;
        !           252:                        goto out;
        !           253:                }
        !           254:                on = mtod(m, int32_t *);
        !           255:                m->m_len = sizeof(*on);
        !           256:                *on = 1;
        !           257:                if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
        !           258:                        goto out;
        !           259:        }
        !           260: 
        !           261:        /*
        !           262:         * Bind the local endpoint to a reserved port,
        !           263:         * because some NFS servers refuse requests from
        !           264:         * non-reserved (non-privileged) ports.
        !           265:         */
        !           266:        m = m_getclr(M_WAIT, MT_SONAME);
        !           267:        sin = mtod(m, struct sockaddr_in *);
        !           268:        sin->sin_len = m->m_len = sizeof(*sin);
        !           269:        sin->sin_family = AF_INET;
        !           270:        sin->sin_addr.s_addr = INADDR_ANY;
        !           271:        tport = IPPORT_RESERVED;
        !           272:        do {
        !           273:                tport--;
        !           274:                sin->sin_port = htons(tport);
        !           275:                error = sobind(so, m);
        !           276:        } while (error == EADDRINUSE &&
        !           277:                         tport > IPPORT_RESERVED / 2);
        !           278:        m_freem(m);
        !           279:        if (error) {
        !           280:                printf("bind failed\n");
        !           281:                goto out;
        !           282:        }
        !           283: 
        !           284:        /*
        !           285:         * Setup socket address for the server.
        !           286:         */
        !           287:        nam = m_get(M_WAIT, MT_SONAME);
        !           288:        if (nam == NULL) {
        !           289:                error = ENOBUFS;
        !           290:                goto out;
        !           291:        }
        !           292:        sin = mtod(nam, struct sockaddr_in *);
        !           293:        bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len));
        !           294: 
        !           295:        /*
        !           296:         * Prepend RPC message header.
        !           297:         */
        !           298:        m = *data;
        !           299:        *data = NULL;
        !           300: #if    DIAGNOSTIC
        !           301:        if ((m->m_flags & M_PKTHDR) == 0)
        !           302:                panic("krpc_call: send data w/o pkthdr");
        !           303:        if (m->m_pkthdr.len < m->m_len)
        !           304:                panic("krpc_call: pkthdr.len not set");
        !           305: #endif
        !           306:        mhead = m_prepend(m, sizeof(*call), M_WAIT);
        !           307:        if (mhead == NULL) {
        !           308:                error = ENOBUFS;
        !           309:                goto out;
        !           310:        }
        !           311:        mhead->m_pkthdr.len += sizeof(*call);
        !           312:        mhead->m_pkthdr.rcvif = NULL;
        !           313: 
        !           314:        /*
        !           315:         * Fill in the RPC header
        !           316:         */
        !           317:        call = mtod(mhead, struct rpc_call *);
        !           318:        bzero((caddr_t)call, sizeof(*call));
        !           319:        xid++;
        !           320:        call->rp_xid = htonl(xid);
        !           321:        /* call->rp_direction = 0; */
        !           322:        call->rp_rpcvers = htonl(2);
        !           323:        call->rp_prog = htonl(prog);
        !           324:        call->rp_vers = htonl(vers);
        !           325:        call->rp_proc = htonl(func);
        !           326:        /* call->rp_auth = 0; */
        !           327:        /* call->rp_verf = 0; */
        !           328: 
        !           329:        /*
        !           330:         * Send it, repeatedly, until a reply is received,
        !           331:         * but delay each re-send by an increasing amount.
        !           332:         * If the delay hits the maximum, start complaining.
        !           333:         */
        !           334:        timo = 0;
        !           335:        for (;;) {
        !           336:                /* Send RPC request (or re-send). */
        !           337:                m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
        !           338:                if (m == NULL) {
        !           339:                        error = ENOBUFS;
        !           340:                        goto out;
        !           341:                }
        !           342:                error = sosend(so, nam, NULL, m, NULL, 0);
        !           343:                if (error) {
        !           344:                        printf("krpc_call: sosend: %d\n", error);
        !           345:                        goto out;
        !           346:                }
        !           347:                m = NULL;
        !           348: 
        !           349:                /* Determine new timeout. */
        !           350:                if (timo < MAX_RESEND_DELAY)
        !           351:                        timo++;
        !           352:                else
        !           353:                        printf("RPC timeout for server 0x%x\n",
        !           354:                               ntohl(sin->sin_addr.s_addr));
        !           355: 
        !           356:                /*
        !           357:                 * Wait for up to timo seconds for a reply.
        !           358:                 * The socket receive timeout was set to 1 second.
        !           359:                 */
        !           360:                secs = timo;
        !           361:                while (secs > 0) {
        !           362:                        if (from) {
        !           363:                                m_freem(from);
        !           364:                                from = NULL;
        !           365:                        }
        !           366:                        if (m) {
        !           367:                                m_freem(m);
        !           368:                                m = NULL;
        !           369:                        }
        !           370:                        auio.uio_resid = len = 1<<16;
        !           371:                        rcvflg = 0;
        !           372:                        error = soreceive(so, &from, &auio, &m, NULL, &rcvflg);
        !           373:                        if (error == EWOULDBLOCK) {
        !           374:                                secs--;
        !           375:                                continue;
        !           376:                        }
        !           377:                        if (error)
        !           378:                                goto out;
        !           379:                        len -= auio.uio_resid;
        !           380: 
        !           381:                        /* Does the reply contain at least a header? */
        !           382:                        if (len < MIN_REPLY_HDR)
        !           383:                                continue;
        !           384:                        if (m->m_len < MIN_REPLY_HDR)
        !           385:                                continue;
        !           386:                        reply = mtod(m, struct rpc_reply *);
        !           387: 
        !           388:                        /* Is it the right reply? */
        !           389:                        if (reply->rp_direction != htonl(RPC_REPLY))
        !           390:                                continue;
        !           391: 
        !           392:                        if (reply->rp_xid != htonl(xid))
        !           393:                                continue;
        !           394: 
        !           395:                        /* Was RPC accepted? (authorization OK) */
        !           396:                        if (reply->rp_astatus != 0) {
        !           397:                                error = ntohl(reply->rp_u.rpu_errno);
        !           398:                                printf("rpc denied, error=%d\n", error);
        !           399:                                continue;
        !           400:                        }
        !           401: 
        !           402:                        /* Did the call succeed? */
        !           403:                        if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) {
        !           404:                                printf("rpc status=%d\n", error);
        !           405:                                continue;
        !           406:                        }
        !           407: 
        !           408:                        goto gotreply;  /* break two levels */
        !           409: 
        !           410:                } /* while secs */
        !           411:        } /* forever send/receive */
        !           412: 
        !           413:        error = ETIMEDOUT;
        !           414:        goto out;
        !           415: 
        !           416:  gotreply:
        !           417: 
        !           418:        /*
        !           419:         * Pull as much as we can into first mbuf, to make
        !           420:         * result buffer contiguous.  Note that if the entire
        !           421:         * result won't fit into one mbuf, you're out of luck.
        !           422:         * XXX - Should not rely on making the entire reply
        !           423:         * contiguous (fix callers instead). -gwr
        !           424:         */
        !           425: #if    DIAGNOSTIC
        !           426:        if ((m->m_flags & M_PKTHDR) == 0)
        !           427:                panic("krpc_call: received pkt w/o header?");
        !           428: #endif
        !           429:        len = m->m_pkthdr.len;
        !           430:        if (m->m_len < len) {
        !           431:                m = m_pullup(m, len);
        !           432:                if (m == NULL) {
        !           433:                        error = ENOBUFS;
        !           434:                        goto out;
        !           435:                }
        !           436:                reply = mtod(m, struct rpc_reply *);
        !           437:        }
        !           438: 
        !           439:        /*
        !           440:         * Strip RPC header
        !           441:         */
        !           442:        len = sizeof(*reply);
        !           443:        if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) {
        !           444:                len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen);
        !           445:                len = (len + 3) & ~3; /* XXX? */
        !           446:        }
        !           447:        m_adj(m, len);
        !           448: 
        !           449:        /* result */
        !           450:        *data = m;
        !           451:        if (from_p) {
        !           452:                *from_p = from;
        !           453:                from = NULL;
        !           454:        }
        !           455: 
        !           456:  out:
        !           457:        if (nam) m_freem(nam);
        !           458:        if (mhead) m_freem(mhead);
        !           459:        if (from) m_freem(from);
        !           460:        soclose(so);
        !           461:        return error;
        !           462: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.