[BACK]Return to krpc_subr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / nfs

Annotation of src/sys/nfs/krpc_subr.c, Revision 1.23

1.23    ! perry       1: /*     $NetBSD: krpc_subr.c,v 1.22 1998/03/01 02:24:27 fvdl Exp $      */
1.3       cgd         2:
1.1       glass       3: /*
1.8       gwr         4:  * Copyright (c) 1995 Gordon Ross, Adam Glass
1.1       glass       5:  * Copyright (c) 1992 Regents of the University of California.
                      6:  * All rights reserved.
                      7:  *
                      8:  * This software was developed by the Computer Systems Engineering group
                      9:  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
                     10:  * contributed to Berkeley.
                     11:  *
                     12:  * Redistribution and use in source and binary forms, with or without
                     13:  * modification, are permitted provided that the following conditions
                     14:  * are met:
                     15:  * 1. Redistributions of source code must retain the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer.
                     17:  * 2. Redistributions in binary form must reproduce the above copyright
                     18:  *    notice, this list of conditions and the following disclaimer in the
                     19:  *    documentation and/or other materials provided with the distribution.
                     20:  * 3. All advertising materials mentioning features or use of this software
                     21:  *    must display the following acknowledgement:
                     22:  *     This product includes software developed by the University of
                     23:  *     California, Lawrence Berkeley Laboratory and its contributors.
                     24:  * 4. Neither the name of the University nor the names of its contributors
                     25:  *    may be used to endorse or promote products derived from this software
                     26:  *    without specific prior written permission.
                     27:  *
                     28:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     29:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     30:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     31:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     32:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     33:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     34:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     35:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     36:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     37:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     38:  * SUCH DAMAGE.
                     39:  *
                     40:  * partially based on:
                     41:  *      libnetboot/rpc.c
                     42:  *               @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL)
                     43:  */
                     44:
                     45: #include <sys/param.h>
1.8       gwr        46: #include <sys/systm.h>
1.1       glass      47: #include <sys/conf.h>
                     48: #include <sys/ioctl.h>
                     49: #include <sys/proc.h>
                     50: #include <sys/mount.h>
                     51: #include <sys/mbuf.h>
1.8       gwr        52: #include <sys/reboot.h>
1.1       glass      53: #include <sys/socket.h>
1.8       gwr        54: #include <sys/socketvar.h>
1.1       glass      55:
                     56: #include <net/if.h>
                     57: #include <netinet/in.h>
                     58:
                     59: #include <nfs/rpcv2.h>
1.7       gwr        60: #include <nfs/krpc.h>
1.9       mycroft    61: #include <nfs/xdr_subs.h>
1.21      drochner   62: #include <nfs/nfsproto.h> /* XXX NFSX_V3FHMAX for next */
1.22      fvdl       63: #include <nfs/nfs.h>
                     64: #include <nfs/nfsmount.h>
1.21      drochner   65: #include <nfs/nfsdiskless.h> /* XXX decl nfs_boot_sendrecv */
1.1       glass      66:
                     67: /*
                     68:  * Kernel support for Sun RPC
                     69:  *
                     70:  * Used currently for bootstrapping in nfs diskless configurations.
                     71:  */
                     72:
                     73: /*
                     74:  * Generic RPC headers
                     75:  */
                     76:
                     77: struct auth_info {
1.10      gwr        78:        u_int32_t       authtype;       /* auth type */
                     79:        u_int32_t       authlen;        /* auth length */
                     80: };
                     81:
                     82: struct auth_unix {
                     83:        int32_t   ua_time;
                     84:        int32_t   ua_hostname;  /* null */
                     85:        int32_t   ua_uid;
                     86:        int32_t   ua_gid;
                     87:        int32_t   ua_gidlist;   /* null */
1.1       glass      88: };
                     89:
                     90: struct rpc_call {
1.8       gwr        91:        u_int32_t       rp_xid;         /* request transaction id */
                     92:        int32_t         rp_direction;   /* call direction (0) */
                     93:        u_int32_t       rp_rpcvers;     /* rpc version (2) */
                     94:        u_int32_t       rp_prog;        /* program */
                     95:        u_int32_t       rp_vers;        /* version */
                     96:        u_int32_t       rp_proc;        /* procedure */
1.10      gwr        97:        struct  auth_info rpc_auth;
                     98:        struct  auth_unix rpc_unix;
                     99:        struct  auth_info rpc_verf;
1.1       glass     100: };
                    101:
                    102: struct rpc_reply {
1.11      cgd       103:        u_int32_t rp_xid;               /* request transaction id */
1.12      fvdl      104:        int32_t  rp_direction;          /* call direction (1) */
                    105:        int32_t  rp_astatus;            /* accept status (0: accepted) */
1.1       glass     106:        union {
1.20      gwr       107:                /* rejected */
                    108:                struct {
                    109:                        u_int32_t rej_stat;
                    110:                        u_int32_t rej_val1;
                    111:                        u_int32_t rej_val2;
                    112:                } rpu_rej;
                    113:                /* accepted */
1.1       glass     114:                struct {
1.10      gwr       115:                        struct auth_info rok_auth;
                    116:                        u_int32_t       rok_status;
                    117:                } rpu_rok;
1.1       glass     118:        } rp_u;
                    119: };
1.20      gwr       120: #define rp_rstat  rp_u.rpu_rej.rej_stat
1.10      gwr       121: #define rp_auth   rp_u.rpu_rok.rok_auth
                    122: #define rp_status rp_u.rpu_rok.rok_status
1.1       glass     123:
                    124: #define MIN_REPLY_HDR 16       /* xid, dir, astat, errno */
                    125:
1.21      drochner  126: static int krpccheck __P((struct mbuf*, void*));
1.2       gwr       127:
                    128: /*
1.1       glass     129:  * Call portmap to lookup a port number for a particular rpc program
1.2       gwr       130:  * Returns non-zero error on failure.
1.1       glass     131:  */
                    132: int
1.19      fvdl      133: krpc_portmap(sin,  prog, vers, proto, portp)
1.7       gwr       134:        struct sockaddr_in *sin;                /* server address */
1.19      fvdl      135:        u_int prog, vers, proto;        /* host order */
1.11      cgd       136:        u_int16_t *portp;       /* network order */
1.1       glass     137: {
                    138:        struct sdata {
1.11      cgd       139:                u_int32_t prog;         /* call program */
                    140:                u_int32_t vers;         /* call version */
                    141:                u_int32_t proto;        /* call protocol */
                    142:                u_int32_t port;         /* call port (unused) */
1.1       glass     143:        } *sdata;
                    144:        struct rdata {
1.8       gwr       145:                u_int16_t pad;
                    146:                u_int16_t port;
1.1       glass     147:        } *rdata;
                    148:        struct mbuf *m;
                    149:        int error;
                    150:
                    151:        /* The portmapper port is fixed. */
                    152:        if (prog == PMAPPROG) {
                    153:                *portp = htons(PMAPPORT);
                    154:                return 0;
                    155:        }
                    156:
1.8       gwr       157:        m = m_get(M_WAIT, MT_DATA);
                    158:        sdata = mtod(m, struct sdata *);
1.1       glass     159:        m->m_len = sizeof(*sdata);
                    160:
                    161:        /* Do the RPC to get it. */
1.9       mycroft   162:        sdata->prog = txdr_unsigned(prog);
                    163:        sdata->vers = txdr_unsigned(vers);
1.19      fvdl      164:        sdata->proto = txdr_unsigned(proto);
1.1       glass     165:        sdata->port = 0;
                    166:
1.7       gwr       167:        sin->sin_port = htons(PMAPPORT);
                    168:        error = krpc_call(sin, PMAPPROG, PMAPVERS,
                    169:                                          PMAPPROC_GETPORT, &m, NULL);
1.1       glass     170:        if (error)
                    171:                return error;
                    172:
1.8       gwr       173:        if (m->m_len < sizeof(*rdata)) {
                    174:                m = m_pullup(m, sizeof(*rdata));
                    175:                if (m == NULL)
                    176:                        return ENOBUFS;
                    177:        }
1.1       glass     178:        rdata = mtod(m, struct rdata *);
                    179:        *portp = rdata->port;
                    180:
                    181:        m_freem(m);
                    182:        return 0;
                    183: }
                    184:
1.21      drochner  185: static int krpccheck(m, context)
                    186: struct mbuf *m;
                    187: void *context;
                    188: {
                    189:        struct rpc_reply *reply;
                    190:
                    191:        /* Does the reply contain at least a header? */
                    192:        if (m->m_pkthdr.len < MIN_REPLY_HDR)
                    193:                return(-1);
                    194:        if (m->m_len < sizeof(struct rpc_reply)) {
                    195:                m = m_pullup(m, sizeof(struct rpc_reply));
                    196:                if (m == NULL)
                    197:                        return(-1);
                    198:        }
                    199:        reply = mtod(m, struct rpc_reply *);
                    200:
                    201:        /* Is it the right reply? */
                    202:        if (reply->rp_direction != txdr_unsigned(RPC_REPLY))
                    203:                return(-1);
                    204:
                    205:        if (reply->rp_xid != txdr_unsigned(*(u_int32_t*)context))
                    206:                return(-1);
                    207:
                    208:        return(0);
                    209: }
                    210:
1.1       glass     211: /*
                    212:  * Do a remote procedure call (RPC) and wait for its reply.
1.7       gwr       213:  * If from_p is non-null, then we are doing broadcast, and
                    214:  * the address from whence the response came is saved there.
1.1       glass     215:  */
                    216: int
1.7       gwr       217: krpc_call(sa, prog, vers, func, data, from_p)
                    218:        struct sockaddr_in *sa;
1.8       gwr       219:        u_int prog, vers, func;
1.1       glass     220:        struct mbuf **data;     /* input/output */
1.7       gwr       221:        struct mbuf **from_p;   /* output */
1.1       glass     222: {
                    223:        struct socket *so;
                    224:        struct sockaddr_in *sin;
1.7       gwr       225:        struct mbuf *m, *nam, *mhead, *from;
1.1       glass     226:        struct rpc_call *call;
                    227:        struct rpc_reply *reply;
1.21      drochner  228:        int error, len;
1.8       gwr       229:        static u_int32_t xid = ~0xFF;
1.11      cgd       230:        u_int16_t tport;
1.1       glass     231:
                    232:        /*
                    233:         * Validate address family.
                    234:         * Sorry, this is INET specific...
                    235:         */
1.7       gwr       236:        if (sa->sin_family != AF_INET)
1.1       glass     237:                return (EAFNOSUPPORT);
                    238:
                    239:        /* Free at end if not null. */
                    240:        nam = mhead = NULL;
1.7       gwr       241:        from = NULL;
1.1       glass     242:
                    243:        /*
                    244:         * Create socket and set its recieve timeout.
                    245:         */
                    246:        if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
                    247:                goto out;
                    248:
1.21      drochner  249:        if ((error = nfs_boot_setrecvtimo(so)))
1.1       glass     250:                goto out;
1.7       gwr       251:
                    252:        /*
                    253:         * Enable broadcast if necessary.
                    254:         */
                    255:        if (from_p) {
1.21      drochner  256:                if ((error = nfs_boot_enbroadcast(so)))
1.7       gwr       257:                        goto out;
1.1       glass     258:        }
                    259:
                    260:        /*
1.5       gwr       261:         * Bind the local endpoint to a reserved port,
                    262:         * because some NFS servers refuse requests from
                    263:         * non-reserved (non-privileged) ports.
                    264:         */
                    265:        tport = IPPORT_RESERVED;
                    266:        do {
                    267:                tport--;
1.21      drochner  268:                error = nfs_boot_sobind_ipport(so, tport);
1.5       gwr       269:        } while (error == EADDRINUSE &&
                    270:                         tport > IPPORT_RESERVED / 2);
                    271:        if (error) {
1.18      christos  272:                printf("bind failed\n");
1.5       gwr       273:                goto out;
                    274:        }
                    275:
                    276:        /*
1.1       glass     277:         * Setup socket address for the server.
                    278:         */
                    279:        nam = m_get(M_WAIT, MT_SONAME);
                    280:        sin = mtod(nam, struct sockaddr_in *);
1.23    ! perry     281:        memcpy((caddr_t)sin, (caddr_t)sa,
1.8       gwr       282:                  (nam->m_len = sa->sin_len));
1.1       glass     283:
                    284:        /*
1.2       gwr       285:         * Prepend RPC message header.
1.1       glass     286:         */
1.8       gwr       287:        mhead = m_gethdr(M_WAIT, MT_DATA);
                    288:        mhead->m_next = *data;
1.1       glass     289:        call = mtod(mhead, struct rpc_call *);
1.8       gwr       290:        mhead->m_len = sizeof(*call);
1.23    ! perry     291:        memset((caddr_t)call, 0, sizeof(*call));
1.10      gwr       292:        /* rpc_call part */
1.7       gwr       293:        xid++;
1.9       mycroft   294:        call->rp_xid = txdr_unsigned(xid);
1.1       glass     295:        /* call->rp_direction = 0; */
1.9       mycroft   296:        call->rp_rpcvers = txdr_unsigned(2);
                    297:        call->rp_prog = txdr_unsigned(prog);
                    298:        call->rp_vers = txdr_unsigned(vers);
                    299:        call->rp_proc = txdr_unsigned(func);
1.10      gwr       300:        /* rpc_auth part (auth_unix as root) */
                    301:        call->rpc_auth.authtype = txdr_unsigned(RPCAUTH_UNIX);
                    302:        call->rpc_auth.authlen  = txdr_unsigned(sizeof(struct auth_unix));
                    303:        /* rpc_verf part (auth_null) */
                    304:        call->rpc_verf.authtype = 0;
                    305:        call->rpc_verf.authlen  = 0;
1.1       glass     306:
                    307:        /*
1.8       gwr       308:         * Setup packet header
                    309:         */
                    310:        len = 0;
                    311:        m = mhead;
                    312:        while (m) {
                    313:                len += m->m_len;
                    314:                m = m->m_next;
                    315:        }
                    316:        mhead->m_pkthdr.len = len;
                    317:        mhead->m_pkthdr.rcvif = NULL;
                    318:
1.21      drochner  319:        error = nfs_boot_sendrecv(so, nam, 0, mhead, krpccheck, &m, &from, &xid);
                    320:        if (error)
1.20      gwr       321:                goto out;
                    322:
1.21      drochner  323:        /* m_pullup() was done in krpccheck() */
                    324:        reply = mtod(m, struct rpc_reply *);
1.1       glass     325:
1.21      drochner  326:        /* Was RPC accepted? (authorization OK) */
                    327:        if (reply->rp_astatus != 0) {
                    328:                /* Note: This is NOT an error code! */
                    329:                error = fxdr_unsigned(u_int32_t, reply->rp_rstat);
                    330:                switch (error) {
                    331:                    case RPC_MISMATCH:
                    332:                        /* .re_status = RPC_VERSMISMATCH; */
                    333:                        error = ERPCMISMATCH;
                    334:                        break;
                    335:                    case RPC_AUTHERR:
                    336:                        /* .re_status = RPC_AUTHERROR; */
                    337:                        error = EAUTH;
                    338:                        break;
                    339:                    default:
                    340:                        /* unexpected */
                    341:                        error = EBADRPC;
                    342:                        break;
1.20      gwr       343:                }
1.21      drochner  344:                goto out;
                    345:        }
1.7       gwr       346:
1.21      drochner  347:        /* Did the call succeed? */
                    348:        if (reply->rp_status != 0) {
                    349:                /* Note: This is NOT an error code! */
                    350:                error = fxdr_unsigned(u_int32_t, reply->rp_status);
                    351:                switch (error) {
                    352:                    case RPC_PROGUNAVAIL:
                    353:                        error = EPROGUNAVAIL;
                    354:                        break;
                    355:                    case RPC_PROGMISMATCH:
                    356:                        error = EPROGMISMATCH;
                    357:                        break;
                    358:                    case RPC_PROCUNAVAIL:
                    359:                        error = EPROCUNAVAIL;
                    360:                        break;
                    361:                    case RPC_GARBAGE:
                    362:                    default:
                    363:                        error = EBADRPC;
1.20      gwr       364:                }
1.21      drochner  365:                goto out;
                    366:        }
1.1       glass     367:
                    368:        /*
1.20      gwr       369:         * OK, we have received a good reply!
1.21      drochner  370:         * Get its length, then strip it off.
1.2       gwr       371:         */
1.8       gwr       372:        len = sizeof(*reply);
1.10      gwr       373:        if (reply->rp_auth.authtype != 0) {
                    374:                len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
1.1       glass     375:                len = (len + 3) & ~3; /* XXX? */
                    376:        }
                    377:        m_adj(m, len);
1.2       gwr       378:
1.1       glass     379:        /* result */
                    380:        *data = m;
1.7       gwr       381:        if (from_p) {
                    382:                *from_p = from;
                    383:                from = NULL;
                    384:        }
1.1       glass     385:
                    386:  out:
                    387:        if (nam) m_freem(nam);
                    388:        if (mhead) m_freem(mhead);
1.7       gwr       389:        if (from) m_freem(from);
1.1       glass     390:        soclose(so);
                    391:        return error;
1.8       gwr       392: }
                    393:
                    394: /*
                    395:  * eXternal Data Representation routines.
                    396:  * (but with non-standard args...)
                    397:  */
                    398:
                    399: /*
                    400:  * String representation for RPC.
                    401:  */
                    402: struct xdr_string {
                    403:        u_int32_t len;          /* length without null or padding */
                    404:        char data[4];   /* data (longer, of course) */
                    405:     /* data is padded to a long-word boundary */
                    406: };
                    407:
                    408: struct mbuf *
                    409: xdr_string_encode(str, len)
                    410:        char *str;
                    411:        int len;
                    412: {
                    413:        struct mbuf *m;
                    414:        struct xdr_string *xs;
                    415:        int dlen;       /* padded string length */
                    416:        int mlen;       /* message length */
                    417:
                    418:        dlen = (len + 3) & ~3;
                    419:        mlen = dlen + 4;
                    420:
1.13      cgd       421:        if (mlen > MCLBYTES)            /* If too big, we just can't do it. */
                    422:                return (NULL);
                    423:
1.8       gwr       424:        m = m_get(M_WAIT, MT_DATA);
                    425:        if (mlen > MLEN) {
                    426:                MCLGET(m, M_WAIT);
1.13      cgd       427:                if ((m->m_flags & M_EXT) == 0) {
                    428:                        (void) m_free(m);       /* There can be only one. */
                    429:                        return (NULL);
                    430:                }
1.8       gwr       431:        }
                    432:        xs = mtod(m, struct xdr_string *);
                    433:        m->m_len = mlen;
1.9       mycroft   434:        xs->len = txdr_unsigned(len);
1.23    ! perry     435:        memcpy(xs->data, str, len);
1.8       gwr       436:        return (m);
                    437: }
                    438:
                    439: struct mbuf *
                    440: xdr_string_decode(m, str, len_p)
                    441:        struct mbuf *m;
                    442:        char *str;
                    443:        int *len_p;             /* bufsize - 1 */
                    444: {
                    445:        struct xdr_string *xs;
                    446:        int mlen;       /* message length */
                    447:        int slen;       /* string length */
                    448:
                    449:        if (m->m_len < 4) {
                    450:                m = m_pullup(m, 4);
                    451:                if (m == NULL)
                    452:                        return (NULL);
                    453:        }
                    454:        xs = mtod(m, struct xdr_string *);
1.9       mycroft   455:        slen = fxdr_unsigned(u_int32_t, xs->len);
1.8       gwr       456:        mlen = 4 + ((slen + 3) & ~3);
                    457:
                    458:        if (slen > *len_p)
                    459:                slen = *len_p;
                    460:        m_copydata(m, 4, slen, str);
                    461:        m_adj(m, mlen);
                    462:
                    463:        str[slen] = '\0';
                    464:        *len_p = slen;
                    465:
                    466:        return (m);
                    467: }
                    468:
                    469:
                    470: /*
                    471:  * Inet address in RPC messages
                    472:  * (Note, really four ints, NOT chars.  Blech.)
                    473:  */
                    474: struct xdr_inaddr {
1.9       mycroft   475:        u_int32_t atype;
                    476:        u_int32_t addr[4];
1.8       gwr       477: };
                    478:
                    479: struct mbuf *
                    480: xdr_inaddr_encode(ia)
                    481:        struct in_addr *ia;             /* already in network order */
                    482: {
                    483:        struct mbuf *m;
                    484:        struct xdr_inaddr *xi;
1.9       mycroft   485:        u_int8_t *cp;
                    486:        u_int32_t *ip;
1.8       gwr       487:
                    488:        m = m_get(M_WAIT, MT_DATA);
                    489:        xi = mtod(m, struct xdr_inaddr *);
                    490:        m->m_len = sizeof(*xi);
1.9       mycroft   491:        xi->atype = txdr_unsigned(1);
1.8       gwr       492:        ip = xi->addr;
1.9       mycroft   493:        cp = (u_int8_t *)&ia->s_addr;
                    494:        *ip++ = txdr_unsigned(*cp++);
                    495:        *ip++ = txdr_unsigned(*cp++);
                    496:        *ip++ = txdr_unsigned(*cp++);
                    497:        *ip++ = txdr_unsigned(*cp++);
1.8       gwr       498:
                    499:        return (m);
                    500: }
                    501:
                    502: struct mbuf *
                    503: xdr_inaddr_decode(m, ia)
                    504:        struct mbuf *m;
                    505:        struct in_addr *ia;             /* already in network order */
                    506: {
                    507:        struct xdr_inaddr *xi;
1.9       mycroft   508:        u_int8_t *cp;
                    509:        u_int32_t *ip;
1.8       gwr       510:
                    511:        if (m->m_len < sizeof(*xi)) {
                    512:                m = m_pullup(m, sizeof(*xi));
                    513:                if (m == NULL)
                    514:                        return (NULL);
                    515:        }
                    516:        xi = mtod(m, struct xdr_inaddr *);
1.9       mycroft   517:        if (xi->atype != txdr_unsigned(1)) {
1.8       gwr       518:                ia->s_addr = INADDR_ANY;
                    519:                goto out;
                    520:        }
                    521:        ip = xi->addr;
1.9       mycroft   522:        cp = (u_int8_t *)&ia->s_addr;
                    523:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    524:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    525:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
                    526:        *cp++ = fxdr_unsigned(u_int8_t, *ip++);
1.8       gwr       527:
                    528: out:
                    529:        m_adj(m, sizeof(*xi));
                    530:        return (m);
1.1       glass     531: }

CVSweb <webmaster@jp.NetBSD.org>