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

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

unix.superglobalmegacorp.com

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